Part 1: RNA

Load RNA samples

Out of 30 samples, we selected 17 for this study. These are the normal tissue samples form the control, the UVA and the UVA+SFN treatment groups. normal tissue samples from the UVB_UA groups as well as tumor samples were excluded from this analysis. Additionally, one of the control samples at Week 2 (baseline) was removed after outlier analysis.
7,219 genes with zero counts in > 80% (> 13 out of 18) of samples were removed. 17,202 out of 24,421 genes were left.

[1] 7219
[1] 17202

Transcripts per kilobase million (TPM) normalization

Next, we noramized the counts. To convert number of hits to the relative abundane of genes in each sample, we used transcripts per kilobase million (TPM) normalization, which is as following for the j-th sample:
1. normilize for gene length: a[i, j] = 1,000*count[i, j]/gene[i, j] length(bp)
2. normalize for seq depth (i.e. total count): a(i, j)/sum(a[, j])
3. multiply by one million
A very good comparison of normalization techniques can be found at the following video:
RPKM, FPKM and TPM, clearly explained

After the normalization, each sample’s total is 1M:

02w_CON_0 02w_SFN_0 02w_SFN_1 02w_UVB_0 02w_UVB_1 15w_CON_0 15w_CON_1 15w_SFN_0 15w_SFN_1 
    1e+06     1e+06     1e+06     1e+06     1e+06     1e+06     1e+06     1e+06     1e+06 
15w_UVB_0 15w_UVB_1 25w_CON_0 25w_CON_1 25w_SFN_0 25w_SFN_1 25w_UVB_0 25w_UVB_1 
    1e+06     1e+06     1e+06     1e+06     1e+06     1e+06     1e+06     1e+06 

Color Legend:
YELLOW: TMP > 10
RED: TMP > 100

Top 100 most abundant RNA molecules

# Separate top 100 abundant genes
tmp <- droplevels(tpm[Geneid %in% levels(tpm$Geneid)[(nrow(tpm) - 99):nrow(tpm)]])

tmp <- melt.data.table(data = tmp,
                       id.vars = 1:2,
                       measure.vars = 3:ncol(tmp),
                       variable.name = "Sample",
                       value.name = "TPM")

tmp$Week <- substr(x = tmp$Sample,
                   start = 1,
                   stop = 3)
tmp$Week <- factor(tmp$Week,
                   levels = unique(tmp$Week))


tmp$Treatment <- substr(x = tmp$Sample,
                        start = 5,
                        stop = 7)
tmp$Treatment <- factor(tmp$Treatment,
                        levels = c("CON", 
                                   "UVB",
                                   "SFN"))

tmp$Replica <- substr(x = tmp$Sample,
                      start = 9,
                      stop = 9)
tmp$Replica <- factor(tmp$Replica,
                      levels = 0:1)

# Plot top 100 abundant genes
p2 <- ggplot(tmp,
             aes(x = TPM,
                 y = Geneid,
                 fill = Treatment,
                 shape = Week)) +
  # facet_wrap(~ Sex, nrow = 1) +
  geom_point(size = 3,
             alpha = 0.5) +
  geom_vline(xintercept = 1,
             linetype = "dashed")
ggplotly(p2)

Bottom 100 least abundant RNA molecules

tmp <- droplevels(tpm[Geneid %in% levels(tpm$Geneid)[1:100]])

tmp <- melt.data.table(data = tmp,
                       id.vars = 1:2,
                       measure.vars = 3:ncol(tmp),
                       variable.name = "Sample",
                       value.name = "TPM")

tmp$Week <- substr(x = tmp$Sample,
                   start = 1,
                   stop = 3)
tmp$Week <- factor(tmp$Week,
                   levels = unique(tmp$Week))


tmp$Treatment <- substr(x = tmp$Sample,
                        start = 5,
                        stop = 7)
tmp$Treatment <- factor(tmp$Treatment,
                        levels = c("CON", 
                                   "UVB",
                                   "SFN"))

tmp$Replica <- substr(x = tmp$Sample,
                      start = 9,
                      stop = 9)
tmp$Replica <- factor(tmp$Replica,
                      levels = 0:1)

# Plot top 100 abundant genes
p3 <- ggplot(tmp,
             aes(x = TPM,
                 y = Geneid,
                 fill = Treatment,
                 shape = Week)) +
  # facet_wrap(~ Sex, nrow = 1) +
  geom_point(size = 3,
             alpha = 0.5) +
  geom_vline(xintercept = 1,
             linetype = "dashed")
ggplotly(p3)

Meta data

dmeta <- data.table(Sample = colnames(dt1)[-c(1:2)])

dmeta$time <- substr(x = dmeta$Sample,
                     start = 1,
                     stop = 3)
dmeta$time <- factor(dmeta$time,
                     levels = c("02w",
                                "15w",
                                "25w"))
dmeta$Week <- factor(dmeta$time,
                     levels = c("02w",
                                "15w",
                                "25w"),
                     labels = c("Week 2",
                                "Week 15",
                                "Week 25"))

dmeta$trt <- substr(x = dmeta$Sample,
                    start = 5,
                    stop = 7)
dmeta$trt <- factor(dmeta$trt,
                    levels = c("CON", 
                               "UVB",
                               "SFN"))
dmeta$Treatment <- factor(dmeta$trt,
                          levels = c("CON", 
                                     "UVB",
                                     "SFN"),
                          labels = c("Negative Control",
                                     "Positive Control (UVB)",
                                     "Sulforaphane (SFN)"))

dmeta$Replica <- substr(x = dmeta$Sample,
                        start = 9,
                        stop = 9)
dmeta$Replica <- factor(dmeta$Replica,
                        levels = 0:1)

datatable(dmeta,
          rownames = FALSE,
          class = "cell-border stripe",
          options = list(pageLength = nrow(dmeta)))

PCA of TPM

NOTE: the distributions are skewed. To make them symmetric, log transformation is often applied. However, there is an issue of zeros. In this instance, we added a small values lambda[i] equal to 1/10 of the smallest non-zero value of i-th gene.

dm.tpm <- as.matrix(tpm[, -c(1:2), with = FALSE])
rownames(dm.tpm) <- tpm$Geneid

# # Remove 02w_CON_1 sample and redo PCA
# dm.tpm <- dm.tpm[, colnames(dm.tpm) != "02w_CON_1"]
# dmeta <- dmeta[dmeta$Sample != "02w_CON_1", ]

# Add lambdas to all values, then take a log
dm.ltpm <- t(apply(X = dm.tpm,
                      MARGIN = 1,
                      FUN = function(a) {
                        lambda <- min(a[a > 0])/10
                        log(a + lambda)
                      }))

# PCA----
m1 <- prcomp(t(dm.ltpm),
             center = TRUE,
             scale. = TRUE)

s1 <- summary(m1)
s1
Importance of components:
                           PC1     PC2     PC3      PC4      PC5      PC6      PC7
Standard deviation     66.5041 61.8206 45.2845 30.42909 28.24422 26.84136 25.01865
Proportion of Variance  0.2571  0.2222  0.1192  0.05383  0.04637  0.04188  0.03639
Cumulative Proportion   0.2571  0.4793  0.5985  0.65232  0.69869  0.74058  0.77696
                            PC8      PC9     PC10     PC11    PC12     PC13     PC14
Standard deviation     23.05989 22.08373 21.24391 20.87624 20.6980 20.28169 19.42403
Proportion of Variance  0.03091  0.02835  0.02624  0.02534  0.0249  0.02391  0.02193
Cumulative Proportion   0.80788  0.83623  0.86246  0.88780  0.9127  0.93662  0.95855
                           PC15     PC16      PC17
Standard deviation     19.14803 18.61200 2.085e-13
Proportion of Variance  0.02131  0.02014 0.000e+00
Cumulative Proportion   0.97986  1.00000 1.000e+00

Pareto chart of variance explained by principal components

imp <- data.table(PC = colnames(s1$importance),
                  Variance = 100*s1$importance[2, ],
                  Cumulative = 100*s1$importance[3, ])
imp$PC <- factor(imp$PC,
                 levels = imp$PC)
p1 <- ggplot(imp,
             aes(x = PC,
                 y = Variance)) +
  geom_bar(stat = "identity",
           fill = "grey",
           color = "black") +
  geom_line(aes(y = rescale(Cumulative,
                            to = c(min(Cumulative)*max(imp$Variance)/100,
                                   max(imp$Variance))),
                group = rep(1, nrow(imp)))) +
  geom_point(aes(y = rescale(Cumulative,
                             to = c(min(Cumulative)*max(imp$Variance)/100,
                                    max(imp$Variance))))) +
  scale_y_continuous("% Variance Explained",
                     breaks = seq(from = 0, 
                                  to = max(imp$Variance), 
                                  by = 5),
                     labels = paste(seq(from = 0, 
                                        to = max(imp$Variance),
                                        by = 5),
                                    "%",
                                    sep = ""),
                     sec.axis = sec_axis(trans = ~.,
                                         name = "% Cumulative Variance",
                                         breaks = seq(from = 0, 
                                                      to = max(imp$Variance), 
                                                      length.out = 5),
                                         labels = paste(seq(from = 0, 
                                                            to = 100, 
                                                            length.out = 5),
                                                        "%",
                                                        sep = ""))) +
  scale_x_discrete("") +
  theme(axis.text.x = element_text(angle = 90,
                                   hjust = 1))

# Save for publication
tiff(filename = "tmp/pca_pareto.tiff",
     height = 6,
     width = 8,
     units = 'in',
     res = 600,
     compression = "lzw+p")
print(p1)
graphics.off()

print(p1)

First 3 principal components, pairwise

# Biplot while keep only the most important variables (Javier)----
# Select PC-s to pliot (PC1 & PC2)
choices <- c(1:3)

# Scores, i.e. points (df.u)
dt.scr <- data.table(m1$x[, choices])
# Add grouping variables
dt.scr$trt <- dmeta$trt
dt.scr$time <- dmeta$time
dt.scr$sample <- dmeta$Sample

# Loadings, i.e. arrows (df.v)
dt.rot <- as.data.frame(m1$rotation[, choices])
dt.rot$feat <- rownames(dt.rot)
dt.rot <- data.table(dt.rot)

# Axis labels
u.axis.labs <- paste(colnames(dt.rot)[choices], 
                     sprintf('(%0.1f%% explained var.)', 
                             100*m1$sdev[choices]^2/sum(m1$sdev^2)))

p1 <- ggplot(data = dt.scr,
             aes(x = PC1,
                 y = PC2,
                 color = trt,
                 shape = time)) +
  geom_point(size = 4,
             alpha = 0.5) +
  scale_x_continuous(u.axis.labs[1]) +
  scale_y_continuous(u.axis.labs[2]) +
  theme(legend.position = "none")
ggplotly(p1)


p2 <- ggplot(data = dt.scr,
             aes(x = PC1,
                 y = PC3,
                 color = trt,
                 shape = time)) +
  geom_point(size = 4,
             alpha = 0.5) +
  scale_x_continuous(u.axis.labs[1]) +
  scale_y_continuous(u.axis.labs[3]) +
  theme(legend.position = "none")
ggplotly(p2)


p3 <- ggplot(data = dt.scr,
             aes(x = PC2,
                 y = PC3,
                 color = trt,
                 shape = time)) +
  geom_point(size = 4,
             alpha = 0.5) +
  scale_x_continuous(u.axis.labs[2]) +
  scale_y_continuous(u.axis.labs[3]) +
  theme(legend.position = "none")
ggplotly(p3)


# Legend only
tmp <- ggplot(data = dt.scr,
             aes(x = PC1,
                 y = PC2,
                 color = trt,
                 shape = time)) +
  geom_point() +
  scale_color_discrete("Treatment") +
  scale_shape_discrete("Week")
p4 <- as_ggplot(get_legend(tmp))

# Save for publication
tiff(filename = "tmp/pca.tiff",
     height = 7,
     width = 9,
     units = 'in',
     res = 600,
     compression = "lzw+p")
grid.arrange(p1, p2, p3, p4, 
             nrow = 2)
graphics.off()

First 3 principal components, 3D

scatterplot3js(x = dt.scr$PC1, 
               y = dt.scr$PC2, 
               z = dt.scr$PC3, 
               color = as.numeric(dt.scr$trt),
               renderer = "auto",
               pch = dt.scr$sample,
               size = 0.1)

Differential expression analysis (DESeq2 pipeline)

Sources:
1. Analyzing RNA-seq data with DESeq2:Interactions
2. Bioconductor Question: DESeq2 time series analysis
We are testing a model with time*treatment interaction. The idea here is to find genes with significant interaction term. That would suggest that the gene expressiondifferences between the treatments depended on time. THere are several possible scenarios:
a. No difference between the negative control and the positive control groups at baseline, significant difference at the later time point. This will show the effect of the disease (UVB radiation, in this case).
b. Significant difference between the control groups at baseline, no difference at the later time point. Same as (a) above.
c. Differences between the positive control and the SFN-treated groups. Here, we are interested in the reversal of UVB effect. Again, the interaction term will need to be significant for the reasons described above.

# Relevel: make all comparisons with the positive control (UVB)
dmeta$trt <- factor(dmeta$trt,
                    levels = c("UVB",
                               "CON",
                               "SFN"))

dtm<- as.matrix(dt1[, dmeta$Sample,
                    with = FALSE])
rownames(dtm) <- dt1$Geneid

dds <- DESeqDataSetFromMatrix(countData = dtm, 
                              colData = dmeta,
                              ~ time + trt + time:trt)
# If all samples contain zeros, geometric means cannot be
# estimated. Change default 'type = "ratio"' to 'type = "poscounts"'.
# Type '?DESeq2::estimateSizeFactors' for more details.
dds <- estimateSizeFactors(object = dds,
                           type = "poscounts")

# Run DESeq----
dds <- DESeq(object = dds,
             # test = "LRT",
             # reduced = ~ time + trt,
             fitType = "local",
             sfType = "ratio",
             parallel = FALSE)
using pre-existing size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
# NOTE (from DESeq help file, section Value):
# A DESeqDataSet object with results stored as metadata columns. 
# These results should accessed by calling the results function. 
# By default this will return the log2 fold changes and p-values
# for the last variable in the design formula. 
# See results for how to access results for other variables.
# In this case, the last term is the interaction term trt:time

# NOTE: 
# Likelihood ratio test (LRT) (chi-squared test) for GLM will only return 
# the results for the difference between the full and the reduced model

resultsNames(dds)
[1] "Intercept"       "time_15w_vs_02w" "time_25w_vs_02w" "trt_CON_vs_UVB" 
[5] "trt_SFN_vs_UVB"  "time15w.trtCON"  "time25w.trtCON"  "time15w.trtSFN" 
[9] "time25w.trtSFN" 
# Model matrix
mm1 <- model.matrix(~ time + trt + time:trt, dmeta)
mm1
   (Intercept) time15w time25w trtCON trtSFN time15w:trtCON time25w:trtCON time15w:trtSFN
1            1       0       0      1      0              0              0              0
2            1       0       0      0      1              0              0              0
3            1       0       0      0      1              0              0              0
4            1       0       0      0      0              0              0              0
5            1       0       0      0      0              0              0              0
6            1       1       0      1      0              1              0              0
7            1       1       0      1      0              1              0              0
8            1       1       0      0      1              0              0              1
9            1       1       0      0      1              0              0              1
10           1       1       0      0      0              0              0              0
11           1       1       0      0      0              0              0              0
12           1       0       1      1      0              0              1              0
13           1       0       1      1      0              0              1              0
14           1       0       1      0      1              0              0              0
15           1       0       1      0      1              0              0              0
16           1       0       1      0      0              0              0              0
17           1       0       1      0      0              0              0              0
   time25w:trtSFN
1               0
2               0
3               0
4               0
5               0
6               0
7               0
8               0
9               0
10              0
11              0
12              0
13              0
14              1
15              1
16              0
17              0
attr(,"assign")
[1] 0 1 1 2 2 3 3 3 3
attr(,"contrasts")
attr(,"contrasts")$time
[1] "contr.treatment"

attr(,"contrasts")$trt
[1] "contr.treatment"
head(mcols(dds))
DataFrame with 6 rows and 50 columns
                 baseMean           baseVar   allZero         dispGeneEst dispGeneIter
                <numeric>         <numeric> <logical>           <numeric>    <numeric>
Xkr4    0.414423785139076 0.750734393874421     FALSE               1e-08            1
Mrpl15   497.506315418383  6139.21631388383     FALSE 0.00292023552394721            6
Lypla1   1316.42450437205   94053.122870121     FALSE 0.00514177871417793           10
Tcea1    362.833336721312  2447.08771392985     FALSE               1e-08           20
Rgs20    412.785226796461  8337.26279018443     FALSE  0.0222228623148068            8
Atp6v1h  1163.12136188358  26870.2895984056     FALSE 0.00473653527254895            9
                    dispFit          dispersion  dispIter dispOutlier             dispMAP
                  <numeric>           <numeric> <integer>   <logical>           <numeric>
Xkr4       2.35686251255345    6.43661011051539         8       FALSE    6.43661011051539
Mrpl15  0.00975181583387631  0.0060101698743299         8       FALSE  0.0060101698743299
Lypla1   0.0074100485818535 0.00604102606581283         9       FALSE 0.00604102606581283
Tcea1    0.0123515065189161 0.00715812241817593         7       FALSE 0.00715812241817593
Rgs20    0.0111228088946145  0.0168637514204584        11       FALSE  0.0168637514204584
Atp6v1h 0.00743062379729061 0.00580961463958366         9       FALSE 0.00580961463958366
               Intercept    time_15w_vs_02w     time_25w_vs_02w      trt_CON_vs_UVB
               <numeric>          <numeric>           <numeric>           <numeric>
Xkr4     -2.359805612164 -0.228477588168501  -0.165844507463528  0.0598562849180821
Mrpl15  9.06594448953328 -0.137408907813809 -0.0412786898053219  -0.308591258014163
Lypla1  10.7337301130648 -0.629677974788472  -0.599280178188303  -0.305684497430534
Tcea1   8.78214921631808 -0.516217579095005  -0.446190172830842  -0.196562316500229
Rgs20   8.98928399842352 -0.547987096260501   -0.45980987283847 -0.0685634893160301
Atp6v1h 10.4068496272689 -0.491695240290437  -0.365919358337453   -0.17807000833384
             trt_SFN_vs_UVB      time15w.trtCON     time25w.trtCON     time15w.trtSFN
                  <numeric>           <numeric>          <numeric>          <numeric>
Xkr4        1.6582080718198    2.45478731530058   3.43262855563513  -1.67076473658365
Mrpl15    0.199168294921519  0.0156586240981802 -0.102536901707458 -0.178149323759463
Lypla1    0.179718039995711   0.281344903276623  0.348189855674569 -0.107101147581259
Tcea1   -0.0830935380769627   0.309506757416714  0.476511703155704  0.271157924759699
Rgs20     0.113854717310148 -0.0460895727086707 -0.119888249480383   0.24522833856804
Atp6v1h  0.0799789915431519   0.246974241692442    0.3213538709111  0.171814404854682
             time25w.trtSFN       SE_Intercept SE_time_15w_vs_02w SE_time_25w_vs_02w
                  <numeric>          <numeric>          <numeric>          <numeric>
Xkr4      -1.57787360996648   2.96284694407196   4.19009832838988   4.19009832833768
Mrpl15  -0.0710688162246861 0.0911721029656416  0.128443851313393   0.12828481198956
Lypla1  -0.0334225250935585 0.0832744171626043  0.118643311639213  0.118734269568226
Tcea1     0.104295727467573 0.0997712835011623  0.143038313778663  0.142999047037131
Rgs20   -0.0021489805803274  0.140429387999271  0.199941844408924  0.199839918784151
Atp6v1h  0.0421037362927887  0.082816070681427  0.117808586333953  0.117641366800501
        SE_trt_CON_vs_UVB SE_trt_SFN_vs_UVB SE_time15w.trtCON SE_time25w.trtCON
                <numeric>         <numeric>         <numeric>         <numeric>
Xkr4     5.13171132899515  4.17888254775382  6.55361338849756   6.5053324829564
Mrpl15  0.161651924073278 0.128745553404475 0.208065870702812 0.207540172422408
Lypla1  0.145519737526484 0.117738852864755 0.188694868576427 0.188378486771387
Tcea1   0.175595965579231 0.142746566195654 0.228119616478045 0.226530264396902
Rgs20   0.244051721146729 0.198791901404911 0.317398591717306 0.316856976912824
Atp6v1h 0.144448031460997 0.117328387791251 0.187086661574303 0.186409051317023
        SE_time15w.trtSFN SE_time25w.trtSFN WaldStatistic_Intercept
                <numeric>         <numeric>               <numeric>
Xkr4     5.91776899533986   5.9177689953029      -0.796465580810876
Mrpl15  0.181401275197653 0.181107411065465         99.437702922678
Lypla1   0.16762877155602 0.167772361896891        128.895889983904
Tcea1   0.202476358816243 0.203686983950883         88.022814863515
Rgs20   0.281821816802482 0.282640507763004         64.012840378327
Atp6v1h  0.16627170341325  0.16643031647693        125.662199880281
        WaldStatistic_time_15w_vs_02w WaldStatistic_time_25w_vs_02w
                            <numeric>                     <numeric>
Xkr4              -0.0545279776897975           -0.0395800991928805
Mrpl15              -1.06979747499584            -0.321773787287314
Lypla1              -5.30731961278428              -5.0472385130895
Tcea1                -3.6089462009025             -3.12023179227889
Rgs20               -2.74073242587354             -2.30089101134551
Atp6v1h             -4.17367914845039             -3.11046503699663
        WaldStatistic_trt_CON_vs_UVB WaldStatistic_trt_SFN_vs_UVB
                           <numeric>                    <numeric>
Xkr4              0.0116640007749233            0.396806575171895
Mrpl15             -1.90898598815487             1.54699164091361
Lypla1             -2.10063942270993             1.52641235771297
Tcea1              -1.11940109701175           -0.582105337392646
Rgs20             -0.280938355992205            0.572733177284935
Atp6v1h            -1.23276175197943            0.681667864434048
        WaldStatistic_time15w.trtCON WaldStatistic_time25w.trtCON
                           <numeric>                    <numeric>
Xkr4               0.374570053157096            0.527663814974626
Mrpl15             0.075258013461256           -0.494058092516009
Lypla1              1.49100452703975             1.84835254620728
Tcea1               1.35677396882921             2.10352336110292
Rgs20             -0.145210388172487           -0.378367081099077
Atp6v1h             1.32010609208693             1.72391774240929
        WaldStatistic_time15w.trtSFN WaldStatistic_time25w.trtSFN WaldPvalue_Intercept
                           <numeric>                    <numeric>            <numeric>
Xkr4              -0.282330171708181           -0.266633187476376    0.425761473479907
Mrpl15            -0.982073161091917            -0.39241252363216                    0
Lypla1            -0.638918644974184           -0.199213533836397                    0
Tcea1               1.33920782823731            0.512039235127185                    0
Rgs20              0.870153848805504         -0.00760322926581116                    0
Atp6v1h             1.03333520573646             0.25298117064282                    0
        WaldPvalue_time_15w_vs_02w WaldPvalue_time_25w_vs_02w WaldPvalue_trt_CON_vs_UVB
                         <numeric>                  <numeric>                 <numeric>
Xkr4             0.956514518769316          0.968427893548228         0.990693684883985
Mrpl15           0.284710479117951          0.747624073744977        0.0562638992384959
Lypla1        1.11249010699918e-07       4.48241630561262e-07        0.0356726306570048
Tcea1         0.000307443353893709        0.00180708779608543         0.262969063182376
Rgs20          0.00613024072810697         0.0213977923150809         0.778757681035553
Atp6v1h       2.99719777251695e-05        0.00186793007683514         0.217664665159797
        WaldPvalue_trt_SFN_vs_UVB WaldPvalue_time15w.trtCON WaldPvalue_time25w.trtCON
                        <numeric>                 <numeric>                 <numeric>
Xkr4            0.691510101678589         0.707980248270468         0.597732692383313
Mrpl15          0.121865261334255         0.940009427107256         0.621265153192805
Lypla1          0.126907201963519         0.135960306359441        0.0645513587969476
Tcea1           0.560495730233128         0.174853041105187        0.0354200453908308
Rgs20           0.566825369916453          0.88454476429304         0.705157919128452
Atp6v1h          0.49544899193699          0.18679959906884        0.0847226938662104
        WaldPvalue_time15w.trtSFN WaldPvalue_time25w.trtSFN  betaConv  betaIter
                        <numeric>                 <numeric> <logical> <numeric>
Xkr4            0.777690352523301         0.789751600479958      TRUE        13
Mrpl15          0.326063806588436         0.694753434090283      TRUE         2
Lypla1          0.522875857997676         0.842095713129838      TRUE         2
Tcea1           0.180503024691872         0.608623550427472      TRUE         2
Rgs20           0.384216333175638         0.993933559205863      TRUE         3
Atp6v1h         0.301447057198772         0.800282763673559      TRUE         2
                deviance  maxCooks
               <numeric> <logical>
Xkr4    25.9033824686373        NA
Mrpl15  165.306361397833        NA
Lypla1  196.962147294101        NA
Tcea1   157.679951768679        NA
Rgs20   178.614721232345        NA
Atp6v1h 192.597108944526        NA

Results

Effect of UVB at Week 2

# res_con_uvb_week2 <- results(dds,
#                              contrast = c(0,0,0,1,0,0,0,0,0),
#                              alpha = 0.1)
# SAME AS:
res_con_uvb_week2 <- results(dds,
                             name = "trt_CON_vs_UVB",
                             alpha = 0.1)
res_con_uvb_week2 <- res_con_uvb_week2[order(res_con_uvb_week2$padj,
                                                   decreasing = FALSE),]
summary(res_con_uvb_week2)

out of 17202 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 1546, 9%
LFC < 0 (down)     : 1537, 8.9%
outliers [1]       : 0, 0%
low counts [2]     : 2335, 14%
(mean count < 2)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
# How many adjusted p-values were less than 0.05?
sum(res_con_uvb_week2$padj < 0.1, 
    na.rm = TRUE)
[1] 3083
# MA plot
# Save for publication
tiff(filename = "tmp/ma_w2_con_uvb.tiff",
     height = 6,
     width = 7,
     units = 'in',
     res = 600,
     compression = "lzw+p")
plotMA(res_con_uvb_week2,
             main = "Control vs. UVB at Week 2",
             alpha = 0.8)
graphics.off()

plotMA(res_con_uvb_week2,
             main = "Control vs. UVB at Week 2",
             alpha = 0.8)

Protective effect of SFN at Week 2

# res_sfn_uvb_week2 <- results(dds,
#                              contrast = c(0,0,0,0,1,0,0,0,0),
#                              alpha = 0.1)
# SAME AS;
res_sfn_uvb_week2 <- results(dds,
                             name = "trt_SFN_vs_UVB",
                             alpha = 0.1)
res_sfn_uvb_week2 <- res_sfn_uvb_week2[order(res_sfn_uvb_week2$padj,
                                                   decreasing = FALSE),]
summary(res_sfn_uvb_week2)

out of 17202 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 26, 0.15%
LFC < 0 (down)     : 35, 0.2%
outliers [1]       : 0, 0%
low counts [2]     : 3669, 21%
(mean count < 5)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
# How many adjusted p-values were less than 0.05?
sum(res_sfn_uvb_week2$padj < 0.1, 
    na.rm = TRUE)
[1] 61
# MA plot
# Save for publication
tiff(filename = "tmp/ma_w2_sfn_uvb.tiff",
     height = 6,
     width = 7,
     units = 'in',
     res = 600,
     compression = "lzw+p")
print(plotMA(res_sfn_uvb_week2,
             main = "UVB+SFN vs UVB at Week 2",
             alpha = 0.8))
NULL
graphics.off()

print(plotMA(res_sfn_uvb_week2,
             main = "UVB+SFN vs UVB at Week 2",
             alpha = 0.8))
NULL

Genes that were significantly differentiated at both comparisons at Week 2

lgene.w2.con <- unique(res_con_uvb_week2@rownames[res_con_uvb_week2$padj < 0.1])
lgene.w2.sfn <- unique(res_sfn_uvb_week2@rownames[res_sfn_uvb_week2$padj < 0.1])
lgene.w2 <- lgene.w2.con[lgene.w2.con %in% lgene.w2.sfn]
lgene.w2 <- lgene.w2 [!is.na(lgene.w2 )]
lgene.w2
 [1] "Utrn"    "Stom"    "Tesc"    "Cited4"  "Cdhr1"   "Slc7a11" "Mki67"   "Cyp26b1"
 [9] "Smc2"    "Mad2l1"  "Slc4a7"  "Ankrd23" "Ifitm3"  "Etv3"    "Pla2g4d" "Fetub"  
[17] "Kif11"   "Ccl6"    "Has3"    "Il19"    "A4galt"  "Otud1"   "Msn"     "Nqo1"   
[25] "Dbf4"    "Cblb"    "Tbc1d24" "Elmo2"   "Cd163"   "Esd"     "Rfx2"    "Gsta1"  
[33] "Slurp1"  "Arntl2"  "Vldlr"   "Tmem173" "Gpx2"    "Slfn9"   "Adh7"    "Sprr2i" 
[41] "Bcl2l15"

Plot of DESeq-normalizedcounts of genes significant in both comparisons at Week 2:

# Get the DESeq-normalize counts
dp1 <- list()
for (i in 1:length(lgene.w2)) {
  out <- plotCounts(dds, 
                    gene = lgene.w2[[i]],
                    intgroup = c("trt",
                                 "time"),
                    returnData = TRUE)
  dp1[[i]] <- data.table(Geneid = lgene.w2[[i]],
                         Sample = rownames(out),
                         out)
}
dp1 <- rbindlist(dp1)
dp1$trt <- factor(dp1$trt,
                  levels = c("CON",
                             "UVB",
                             "SFN"))
dp1$time <- factor(dp1$time,
                   levels = c("02w",
                              "15w",
                              "25w"),
                   labels = c("Week 2",
                              "Week 15",
                              "Week 25"))
dp1$Geneid <- factor(dp1$Geneid,
                     levels = lgene.w2)
dp1[, mu := mean(count,
                 na.rm = TRUE),
    by = c("Geneid",
           "trt",
           "time")]
dmu <- unique(dp1[, -c("Sample",
                       "count")])
datatable(head(dmu),
          rownames = FALSE,
          class = "cell-border stripe") %>% 
  formatRound(columns = 4,
              digits = 2)
List of 1
 $ axis.text.x:List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 1
  ..$ vjust        : NULL
  ..$ angle        : num 45
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi FALSE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 - attr(*, "class")= chr [1:2] "theme" "gg"
 - attr(*, "complete")= logi FALSE
 - attr(*, "validate")= logi TRUE

Did down-up-down trend persist?

dp1.tmp <- dp1[dp1$Geneid %in% unique(dmu.w2$Geneid[dmu.w2$up.dn]), ]
dmu.tmp <- dmu[dmu$Geneid %in% unique(dmu.w2$Geneid[dmu.w2$up.dn]), ]
p1 <- ggplot(dp1.tmp,
             aes(x = time,
                 y = count,
                 group = trt,
                 fill = trt)) +
  facet_wrap(~ Geneid,
             scale = "free_y") +
  geom_point(position = position_dodge(0.5),
             shape = 21,
             size = 5,
             color = "black") +
  geom_line(data = dmu.tmp,
            aes(x = time,
                y = mu,
                group = trt,
                colour = trt),
            position = position_dodge(0.5),
            alpha = 0.5,
            size = 2) +
  scale_x_discrete("") +
  scale_y_continuous("DESeq-Normalized Counts") +
  scale_fill_discrete("Treatment")
print(p1)

List of 1
 $ axis.text.x:List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 1
  ..$ vjust        : NULL
  ..$ angle        : num 45
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi FALSE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 - attr(*, "class")= chr [1:2] "theme" "gg"
 - attr(*, "complete")= logi FALSE
 - attr(*, "validate")= logi TRUE

Did up-down-up trend persist?

dp1.tmp <- dp1[dp1$Geneid %in% unique(dmu.w2$Geneid[dmu.w2$dn.up]), ]
dmu.tmp <- dmu[dmu$Geneid %in% unique(dmu.w2$Geneid[dmu.w2$dn.up]), ]
p1 <- ggplot(dp1.tmp,
             aes(x = time,
                 y = count,
                 group = trt,
                 fill = trt)) +
  facet_wrap(~ Geneid,
             scale = "free_y") +
  geom_point(position = position_dodge(0.5),
             shape = 21,
             size = 5,
             color = "black") +
  geom_line(data = dmu.tmp,
            aes(x = time,
                y = mu,
                group = trt,
                colour = trt),
            position = position_dodge(0.5),
            alpha = 0.5,
            size = 2) +
  scale_x_discrete("") +
  scale_y_continuous("DESeq-Normalized Counts") +
  scale_fill_discrete("Treatment")
print(p1)

In many of these genes, UVB+SFN moved closer to UVB over time.

Heatmap for Week 2 differentially methylated genes

up.dn.w2 <- unique(as.character(dmu.w2$Geneid[dmu.w2$up.dn]))
dn.up.w2 <- unique(as.character(dmu.w2$Geneid[dmu.w2$dn.up]))
ll <- unique(c(up.dn.w2,
               dn.up.w2))
# 36 genes

con_uvb_week2 <- data.table(Geneid = res_con_uvb_week2@rownames,
                            log2FoldChange = res_con_uvb_week2@listData$log2FoldChange)

sfn_uvb_week2 <- data.table(Geneid = res_sfn_uvb_week2@rownames,
                            log2FoldChange = -res_sfn_uvb_week2@listData$log2FoldChange)

t1 <- merge(con_uvb_week2[con_uvb_week2$Geneid %in% ll, ],
            sfn_uvb_week2[sfn_uvb_week2$Geneid %in% ll, ],
            by = "Geneid")
colnames(t1)[2:3] <- c("Control vs. UVB",
                       "UVB vs. SFN+UVB")
t1 <- t1[order(t1$`Control vs. UVB`,
               decreasing = TRUE), ]
write.csv(t1,
          file = "tmp/w2_sign_changes.csv",
          row.names = FALSE)

ll <- melt.data.table(data = t1,
                      id.vars = 1,
                      measure.vars = 2:3,
                      variable.name = "Comparison",
                      value.name = "Gene Expression Diff")
ll$Comparison <- factor(ll$Comparison,
                        levels = c("Control vs. UVB",
                                   "UVB vs. SFN+UVB"))
lvls <- ll[ll$Comparison == "Control vs. UVB", ]
ll$Geneid <- factor(ll$Geneid,
                    levels = lvls$Geneid[order(lvls$`Gene Expression Diff`)])

# Add dendrogram----
dt.dndr <- data.frame(t1[Geneid %in% levels(ll$Geneid), ])
rownames(dt.dndr) <- dt.dndr$Gene
dt.dndr <- dt.dndr[, -1]

# Compute distances between genes----
sampleDists <- dist(dt.dndr)

# Make dendrogram data----
dhc <- as.dendrogram(hclust(d = sampleDists),
                     horiz = TRUE)
ddata <- dendro_data(dhc, 
                     type = "rectangle")

# Segment data----
dtp1 <- segment(ddata)

# Hitmap data----
dtp2 <- ll
dtp2$Geneid <- factor(dtp2$Geneid,
                      levels = ddata$labels$label)

offset.size <- 4

p1 <- ggplot(data = dtp2) +
  coord_polar("y",
              start = -0.3,
              direction = -1) +
  geom_tile(aes(x =  as.numeric(Comparison),
                y = Geneid, 
                fill = `Gene Expression Diff`),
            color = "white") +
  geom_text(data = dtp2[Comparison == "Control vs. UVB", ],
            aes(x = rep(1.75,
                        nlevels(Geneid)),
                y = Geneid,
                angle = 90 + seq(from = 30,
                                 to = 330,
                                 length.out = nlevels(Geneid))[as.numeric(Geneid)] + 
                  offset.size,
                label = unique(Geneid)),
            hjust = 0) +
  geom_text(data = dtp2[Geneid == levels(dtp2$Geneid)[1], ],
            aes(x = 1:nlevels(Comparison),
                y = rep(-offset.size,
                        nlevels(Comparison)),
                angle = 0,
                label = levels(Comparison)),
            hjust = 1,
            size = 5) +
  scale_fill_gradient2(low = "red", 
                       high = "green", 
                       mid = "grey", 
                       midpoint = 0, 
                       name = "") +
  scale_y_discrete("",
                   expand = c(0, 0)) +
  theme(plot.title = element_text(hjust = 0.5),
        axis.title.x = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        panel.background = element_blank(),
        legend.position = "bottom",
        legend.text = element_text(size = 15),
        legend.direction = "horizontal",
        legend.key.width = unit(1, "in"),
        legend.key.height = unit(0.3, "in")) +
  geom_segment(data = dtp1,
               aes(x = -sqrt(y) + 0.5,
                   y = x, 
                   xend = -sqrt(yend) + 0.5,
                   yend = xend),
               size = 1) 

tiff(filename = "tmp/skin_ubv_w2_sfn_hitmap_with_phylo.tiff",
     height = 8,
     width = 8,
     units = 'in',
     res = 600,
     compression = "lzw+p")
plot(p1)
graphics.off()

print(p1)

Venn Diagram, Week 2

# 1. Ctrl vs. UVB
# adjusted p-value < 0.1
# LFC > 0 (up)       : 1546, 9%
# LFC < 0 (down)     : 1537, 8.9%
# 23 genes down-up-down

# 2. SFN+UVB vs. UVB
# adjusted p-value < 0.1
# LFC > 0 (up)       : 26, 0.15%
# LFC < 0 (down)     : 35, 0.2%
# 13 gens up-down-up

p1 <- ggplot() +
  geom_circle(aes(x0 = c(1, 2, 1, 2),
                  y0 = c(1, 1, 4, 4),
                  r = rep(1, 4),
                  color = factor(c(2, 1, 1, 2))),
              size = 2) +
  geom_text(aes(x = rep(c(0.5, 1.5, 2.5), 2),
                y = rep(c(1, 4), each = 3),
                label = format(c(26, 13, 35, 1546, 23, 1537),
                               big.mark = ","))) +
  scale_color_manual(values = c("green", "red")) +
  theme_void() +
  theme(legend.position = "none")

tiff(filename = "tmp/skin_ubv_sfn_w2_venn.tiff",
     height = 6,
     width = 4,
     units = 'in',
     res = 600,
     compression = "lzw+p")
plot(p1)
graphics.off()

print(p1)

Effect of UVB at Week 15

res_con_uvb_week15 <- results(dds,
                              contrast = c(0,0,0,1,0,1,0,0,0),
                              alpha = 0.1)
res_con_uvb_week15 <- res_con_uvb_week15[order(res_con_uvb_week15$padj,
                                               decreasing = FALSE),]
summary(res_con_uvb_week15)

out of 17202 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 1513, 8.8%
LFC < 0 (down)     : 1463, 8.5%
outliers [1]       : 0, 0%
low counts [2]     : 2668, 16%
(mean count < 2)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
# out of 17202 with nonzero total read count
# adjusted p-value < 0.1
# LFC > 0 (up)       : 1513, 8.8%
# LFC < 0 (down)     : 1463, 8.5%
# outliers [1]       : 0, 0%
# low counts [2]     : 2668, 16%
# (mean count < 2)

# How many adjusted p-values were less than 0.01?
sum(res_con_uvb_week15$padj < 0.1, 
    na.rm = TRUE)
[1] 2976
# 2976

# NOT THE SAME AS?!!!:
res_con_uvb_week15.1 <- results(dds,
                                contrast = list("trt_CON_vs_UVB",
                                                "time15w.trtCON"),
                                alpha = 0.1)
res_con_uvb_week15.1 <- res_con_uvb_week15.1[order(res_con_uvb_week15.1$padj,
                                                   decreasing = FALSE),]
summary(res_con_uvb_week15.1)

out of 17202 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 469, 2.7%
LFC < 0 (down)     : 455, 2.6%
outliers [1]       : 0, 0%
low counts [2]     : 4002, 23%
(mean count < 6)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
# out of 17202 with nonzero total read count
# adjusted p-value < 0.1
# LFC > 0 (up)       : 469, 2.7%
# LFC < 0 (down)     : 455, 2.6%
# outliers [1]       : 0, 0%
# low counts [2]     : 4002, 23%
# (mean count < 6)

# How many adjusted p-values were less than 0.01?
sum(res_con_uvb_week15.1$padj < 0.1, 
    na.rm = TRUE)
[1] 924
# 924

# MA plot
# Save for publication
tiff(filename = "tmp/ma_w15_con_uvb.tiff",
     height = 6,
     width = 7,
     units = 'in',
     res = 600,
     compression = "lzw+p")
plotMA(res_con_uvb_week15,
       main = "Control vs. UVB at Week 15",
       alpha = 0.8)
graphics.off()

plotMA(res_con_uvb_week15,
       main = "Control vs. UVB at Week 15",
       alpha = 0.8)

Protective effect of SFN at Week 15

res_sfn_uvb_week15 <- results(dds,
                              contrast = c(0,0,0,0,1,0,0,1,0),
                              alpha = 0.1)
res_sfn_uvb_week15 <- res_sfn_uvb_week15[order(res_sfn_uvb_week15$padj,
                                               decreasing = FALSE),]
summary(res_sfn_uvb_week15)

out of 17202 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 20, 0.12%
LFC < 0 (down)     : 10, 0.058%
outliers [1]       : 0, 0%
low counts [2]     : 7004, 41%
(mean count < 53)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
# out of 17202 with nonzero total read count
# adjusted p-value < 0.1
# LFC > 0 (up)       : 20, 0.12%
# LFC < 0 (down)     : 10, 0.058%
# outliers [1]       : 0, 0%
# low counts [2]     : 7004, 41%
# (mean count < 53)

# How many adjusted p-values were less than 0.05?
sum(res_sfn_uvb_week15$padj < 0.1, 
    na.rm = TRUE)
[1] 30
# 30

# NOT THE SAME AS!!!:
res_sfn_uvb_week15.1 <- results(dds,
                                contrast = list("trt_SFN_vs_UVB",
                                                "time15w.trtSFN"),
                                alpha = 0.1)
res_sfn_uvb_week15.1 <- res_sfn_uvb_week15.1[order(res_sfn_uvb_week15.1$padj,
                                                   decreasing = FALSE),]
summary(res_sfn_uvb_week15.1)

out of 17202 with nonzero total read count
adjusted p-value < 0.1
LFC > 0 (up)       : 14, 0.081%
LFC < 0 (down)     : 24, 0.14%
outliers [1]       : 0, 0%
low counts [2]     : 3335, 19%
(mean count < 4)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
# out of 17202 with nonzero total read count
# adjusted p-value < 0.1
# LFC > 0 (up)       : 14, 0.081%
# LFC < 0 (down)     : 24, 0.14%
# outliers [1]       : 0, 0%
# low counts [2]     : 3335, 19%
# (mean count < 4)

# How many adjusted p-values were less than 0.05?
sum(res_sfn_uvb_week15.1$padj < 0.1, 
    na.rm = TRUE)
[1] 38
# 38

# MA plot
# Save for publication
tiff(filename = "tmp/ma_w2_sfn_uvb.tiff",
     height = 6,
     width = 7,
     units = 'in',
     res = 600,
     compression = "lzw+p")
print(plotMA(res_sfn_uvb_week15,
             main = "UVB+SFN vs UVB at Week 15",
             alpha = 0.8))
NULL
graphics.off()

print(plotMA(res_sfn_uvb_week15,
             main = "UVB+SFN vs UVB at Week 15",
             alpha = 0.8))
NULL

Genes that were significantly differentiated at both comparisons at Week 15

lgene.w15.con <- unique(res_con_uvb_week15@rownames[res_con_uvb_week15$padj < 0.1])
lgene.w15.sfn <- unique(res_sfn_uvb_week15@rownames[res_sfn_uvb_week15$padj < 0.1])
lgene.w15 <- lgene.w15.con[lgene.w15.con %in% lgene.w15.sfn]
lgene.w15 <- lgene.w15 [!is.na(lgene.w15 )]
length(unique(lgene.w15))
[1] 15

Plot of DESeq-normalizedcounts of genes significant in both comparisons at Week 15:

# Get the DESeq-normalize counts
dp1 <- list()
for (i in 1:length(lgene.w15)) {
  out <- plotCounts(dds, 
                    gene = lgene.w15[[i]],
                    intgroup = c("trt",
                                 "time"),
                    returnData = TRUE)
  dp1[[i]] <- data.table(Geneid = lgene.w15[[i]],
                         Sample = rownames(out),
                         out)
}
dp1 <- rbindlist(dp1)
dp1$trt <- factor(dp1$trt,
                  levels = c("CON",
                             "UVB",
                             "SFN"))
dp1$time <- factor(dp1$time,
                   levels = c("02w",
                              "15w",
                              "25w"),
                   labels = c("Week 2",
                              "Week 15",
                              "Week 25"))
dp1$Geneid <- factor(dp1$Geneid,
                     levels = lgene.w15)
dp1[, mu := mean(count,
                 na.rm = TRUE),
    by = c("Geneid",
           "trt",
           "time")]
dmu <- unique(dp1[, -c("Sample",
                       "count")])
datatable(head(dmu),
          rownames = FALSE,
          class = "cell-border stripe") %>% 
  formatRound(columns = 4,
              digits = 2)
List of 1
 $ axis.text.x:List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 1
  ..$ vjust        : NULL
  ..$ angle        : num 45
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi FALSE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 - attr(*, "class")= chr [1:2] "theme" "gg"
 - attr(*, "complete")= logi FALSE
 - attr(*, "validate")= logi TRUE

Did down-up-down trend persist?

dp1.tmp <- dp1[dp1$Geneid %in% unique(dmu.w15$Geneid[dmu.w15$up.dn]), ]
dmu.tmp <- dmu[dmu$Geneid %in% unique(dmu.w15$Geneid[dmu.w15$up.dn]), ]
p1 <- ggplot(dp1.tmp,
             aes(x = time,
                 y = count,
                 group = trt,
                 fill = trt)) +
  facet_wrap(~ Geneid,
             scale = "free_y") +
  geom_point(position = position_dodge(0.5),
             shape = 21,
             size = 5,
             color = "black") +
  geom_line(data = dmu.tmp,
            aes(x = time,
                y = mu,
                group = trt,
                colour = trt),
            position = position_dodge(0.5),
            alpha = 0.5,
            size = 2) +
  scale_x_discrete("") +
  scale_y_continuous("DESeq-Normalized Counts") +
  scale_fill_discrete("Treatment")
print(p1)

List of 1
 $ axis.text.x:List of 11
  ..$ family       : NULL
  ..$ face         : NULL
  ..$ colour       : NULL
  ..$ size         : NULL
  ..$ hjust        : num 1
  ..$ vjust        : NULL
  ..$ angle        : num 45
  ..$ lineheight   : NULL
  ..$ margin       : NULL
  ..$ debug        : NULL
  ..$ inherit.blank: logi FALSE
  ..- attr(*, "class")= chr [1:2] "element_text" "element"
 - attr(*, "class")= chr [1:2] "theme" "gg"
 - attr(*, "complete")= logi FALSE
 - attr(*, "validate")= logi TRUE

Did up-down-up trend persist?

dp1.tmp <- dp1[dp1$Geneid %in% unique(dmu.w15$Geneid[dmu.w15$dn.up]), ]
dmu.tmp <- dmu[dmu$Geneid %in% unique(dmu.w15$Geneid[dmu.w15$dn.up]), ]
p1 <- ggplot(dp1.tmp,
             aes(x = time,
                 y = count,
                 group = trt,
                 fill = trt)) +
  facet_wrap(~ Geneid,
             scale = "free_y") +
  geom_point(position = position_dodge(0.5),
             shape = 21,
             size = 5,
             color = "black") +
  geom_line(data = dmu.tmp,
            aes(x = time,
                y = mu,
                group = trt,
                colour = trt),
            position = position_dodge(0.5),
            alpha = 0.5,
            size = 2) +
  scale_x_discrete("") +
  scale_y_continuous("DESeq-Normalized Counts") +
  scale_fill_discrete("Treatment")
print(p1)

Heatmap for Week 15 differentially methylated genes

up.dn.w15 <- unique(as.character(dmu.w15$Geneid[dmu.w15$up.dn]))
dn.up.w15 <- unique(as.character(dmu.w15$Geneid[dmu.w15$dn.up]))
ll <- unique(c(up.dn.w15,
               dn.up.w15))
# 16 genes

con_uvb_week15 <- data.table(Geneid = res_con_uvb_week15@rownames,
                             log2FoldChange = res_con_uvb_week15@listData$log2FoldChange)

sfn_uvb_week15 <- data.table(Geneid = res_sfn_uvb_week15@rownames,
                             log2FoldChange = -res_sfn_uvb_week15@listData$log2FoldChange)

t1 <- merge(con_uvb_week15[con_uvb_week15$Geneid %in% ll, ],
            sfn_uvb_week15[sfn_uvb_week15$Geneid %in% ll, ],
            by = "Geneid")
colnames(t1)[2:3] <- c("Control vs. UVB",
                       "UVB vs. SFN+UVB")
t1 <- t1[order(t1$`Control vs. UVB`,
               decreasing = TRUE), ]
write.csv(t1,
          file = "tmp/w15_sign_changes.csv",
          row.names = FALSE)

ll <- melt.data.table(data = t1,
                      id.vars = 1,
                      measure.vars = 2:3,
                      variable.name = "Comparison",
                      value.name = "Gene Expression Diff")
ll$Comparison <- factor(ll$Comparison,
                        levels = c("Control vs. UVB",
                                   "UVB vs. SFN+UVB"))
lvls <- ll[ll$Comparison == "Control vs. UVB", ]
ll$Geneid <- factor(ll$Geneid,
                    levels = lvls$Geneid[order(lvls$`Gene Expression Diff`)])

# Add dendrogram----
dt.dndr <- data.frame(t1[Geneid %in% levels(ll$Geneid), ])
rownames(dt.dndr) <- dt.dndr$Gene
dt.dndr <- dt.dndr[, -1]

# Compute distances between genes----
sampleDists <- dist(dt.dndr)

# Make dendrogram data----
dhc <- as.dendrogram(hclust(d = sampleDists),
                     horiz = TRUE)
ddata <- dendro_data(dhc, 
                     type = "rectangle")

# Segment data----
dtp1 <- segment(ddata)

# Hitmap data----
dtp2 <- ll
dtp2$Geneid <- factor(dtp2$Geneid,
                      levels = ddata$labels$label)

offset.size <- 4

p1 <- ggplot(data = dtp2) +
  coord_polar("y",
              start = -0.3,
              direction = -1) +
  geom_tile(aes(x =  as.numeric(Comparison),
                y = Geneid, 
                fill = `Gene Expression Diff`),
            color = "white") +
  geom_text(data = dtp2[Comparison == "Control vs. UVB", ],
            aes(x = rep(1.75,
                        nlevels(Geneid)),
                y = Geneid,
                angle = 90 + seq(from = 90,
                                 to = 330,
                                 length.out = nlevels(Geneid))[as.numeric(Geneid)] + 
                  offset.size,
                label = unique(Geneid)),
            hjust = 0) +
  geom_text(data = dtp2[Geneid == levels(dtp2$Geneid)[1], ],
            aes(x = 1:nlevels(Comparison),
                y = rep(-offset.size,
                        nlevels(Comparison)),
                angle = 0,
                label = levels(Comparison)),
            hjust = 1,
            size = 5) +
  scale_fill_gradient2(low = "red", 
                       high = "green", 
                       mid = "grey", 
                       midpoint = 0, 
                       name = "") +
  scale_y_discrete("",
                   expand = c(0, 0)) +
  theme(plot.title = element_text(hjust = 0.5),
        axis.title.x = element_blank(),
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.title.y = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank(),
        panel.background = element_blank(),
        legend.position = "bottom",
        legend.text = element_text(size = 15),
        legend.direction = "horizontal",
        legend.key.width = unit(1, "in"),
        legend.key.height = unit(0.3, "in")) +
  geom_segment(data = dtp1,
               aes(x = -sqrt(y) + 0.5,
                   y = x, 
                   xend = -sqrt(yend) + 0.5,
                   yend = xend),
               size = 1) 

tiff(filename = "tmp/skin_ubv_w15_sfn_hitmap_with_phylo.tiff",
     height = 8,
     width = 8,
     units = 'in',
     res = 600,
     compression = "lzw+p")
plot(p1)
graphics.off()

print(p1)

Venn Diagram, Week 15

# out of 17202 with nonzero total read count
# 1. Ctrl vs. UVB
# adjusted p-value < 0.1
# LFC > 0 (up)       : 1513, 8.8%
# LFC < 0 (down)     : 1463, 8.5%
# 2 genes down-up-down

# 2. SFN+UVB vs. UVB
# adjusted p-value < 0.1
# LFC > 0 (up)       : 20, 0.12%
# LFC < 0 (down)     : 10, 0.058%
# 9 gens up-down-up

p1 <- ggplot() +
  geom_circle(aes(x0 = c(1, 2, 1, 2),
                  y0 = c(1, 1, 4, 4),
                  r = rep(1, 4),
                  color = factor(c(2, 1, 1, 2))),
              size = 2) +
  geom_text(aes(x = rep(c(0.5, 1.5, 2.5), 2),
                y = rep(c(1, 4), each = 3),
                label = format(c(20, 9, 10, 1513, 2, 1463),
                               big.mark = ","))) +
  scale_color_manual(values = c("green", "red")) +
  theme_void() +
  theme(legend.position = "none")

tiff(filename = "tmp/skin_ubv_sfn_w2_venn.tiff",
     height = 6,
     width = 4,
     units = 'in',
     res = 600,
     compression = "lzw+p")
plot(p1)
graphics.off()

print(p1)

Interactions terms

Tests if the effect of NOT treating with UVB vs. treating with UVB is different at Week 15 compared to Week 2:

res_int_con_uvb_week <- results(dds, 
                                name = "time15w.trtCON",
                                alpha = 0.1)
res_int_con_uvb_week <- res_int_con_uvb_week[order(res_int_con_uvb_week$padj,
                                                   decreasing = FALSE),]
print(res_int_con_uvb_week)
summary(res_int_con_uvb_week)

# How many adjusted p-values were less than 0.05?
sum(res_int_con_uvb_week$padj < 0.1, 
    na.rm = TRUE)

# MA plot
print(plotMA(res_int_con_uvb_week,
             main = "(Control vs. UVB) x TIme Interaction",
             alpha = 0.9))

Tests if the effect of treating with UVB+SFN vs. treating with UVB is different at Week 15 compared to Week 2:

res_int_sfn_uvb_week <- results(dds, 
                                name = "time15w.trtSFN",
                                alpha = 0.1)
res_int_sfn_uvb_week <- res_int_sfn_uvb_week[order(res_int_sfn_uvb_week$padj,
                                                   decreasing = FALSE),]
print(res_int_sfn_uvb_week)
summary(res_int_sfn_uvb_week)

# How many adjusted p-values were less than 0.05?
sum(res_int_sfn_uvb_week$padj < 0.1, 
    na.rm = TRUE)

# MA plot
print(plotMA(res_int_sfn_uvb_week))

# NOTE: same as 
# res <- results(dds, 
#                   alpha = 0.05)
# res <- res[order(res$padj, decreasing = FALSE),]
# res

NOTE: By default, the results(dds)* prints the results for the last level of the last term, i.e. here it was for for the interaction term SFN vs. UVB at Week 15 vs. Week 2.

Genes with both interactions being significant

lgene.con <- unique(res_int_con_uvb_week@rownames[res_int_con_uvb_week$padj < 0.1])
lgene.sfn <- unique(res_int_sfn_uvb_week@rownames[res_int_sfn_uvb_week$padj < 0.1])
lgene <- lgene.con[lgene.con %in% lgene.sfn]
lgene <- lgene[!is.na(lgene)]
lgene

Plot of DESeq-normalizedcounts of genes with smallest adjusted p-value for the interaction term:

# Get the DESeq-normalize counts
dp1 <- list()
for (i in 1:length(lgene)) {
  out <- plotCounts(dds, 
                    gene = lgene[[i]],
                    intgroup = c("trt",
                                 "time"),
                    returnData = TRUE)
  dp1[[i]] <- data.table(Geneid = lgene[[i]],
                         Sample = rownames(out),
                         out)
}
dp1 <- rbindlist(dp1)
dp1$trt <- factor(dp1$trt,
                  levels = c("CON",
                             "UVB",
                             "SFN"))
dp1$time <- factor(dp1$time,
                   levels = c("02w",
                              "15w"),
                   labels = c("Week 2",
                              "Week 15"))
dp1$Geneid <- factor(dp1$Geneid,
                     levels = lgene)
dp1[, mu := mean(count,
                 na.rm = TRUE),
    by = c("Geneid",
           "trt",
           "time")]
dmu <- unique(dp1[, -c("Sample",
                       "count")])

p1 <- ggplot(dp1,
             aes(x = time,
                 y = count,
                 group = trt,
                 fill = trt)) +
  facet_wrap(~ Geneid,
             scale = "free_y") +
  geom_point(position = position_dodge(0.5),
             shape = 21,
             size = 5,
             color = "black") +
  geom_line(data = dmu,
            aes(x = time,
                y = mu,
                group = trt,
                colour = trt),
            position = position_dodge(0.5),
            alpha = 0.5,
            size = 2) +
  scale_x_discrete("") +
  scale_y_continuous("DESeq-Normalized Counts") +
  scale_fill_discrete("Treatment")
print(p1)

Compare to the plot of TPM-normalizedcounts of genes with smallest adjusted p-value for the interaction term:

# Examine TPM values for the same genes
tmp <- tpm[Geneid %in% lgene, ]
tmp$Geneid <- factor(tmp$Geneid,
                     levels = lgene)
tmp <- melt.data.table(data = tmp,
                       id.vars = 1,
                       measure.vars = 3:ncol(tmp),
                       variable.name = "Sample",
                       value.name = "TPM")
tmp <- merge(dmeta,
             tmp,
             by = "Sample")

p1 <- ggplot(tmp,
             aes(x = Week,
                 y = TPM,
                 fill = Treatment,
                 group = Treatment)) +
  facet_wrap(~ Geneid,
             scales = "free_y") +
  geom_point(position = position_dodge(0.5),
             shape = 21,
             size = 5,
             color = "black")+
  scale_x_discrete("")
plot(p1)

Session Information

sessionInfo()
LS0tDQp0aXRsZTogIlNraW4gVVZCIFNLSDEgbW91c2UgbW9kZWwgdHJlYXRlZCB3aXRoIFNGTiAiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KLS0tDQoNCiMgUGFydCAxOiBSTkENCmBgYHtyIGhlYWRlciwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGVycm9yID0gRkFMU0UsIHdhcm5pbmcgID1GQUxTRX0NCiMgaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJCaW9jTWFuYWdlciIsIHF1aWV0bHkgPSBUUlVFKSkNCiMgICAgIGluc3RhbGwucGFja2FnZXMoIkJpb2NNYW5hZ2VyIikNCiMgQmlvY01hbmFnZXI6Omluc3RhbGwoIkRFU2VxMiIpDQoNCnJlcXVpcmUoa25pdHIpDQpyZXF1aXJlKGRhdGEudGFibGUpDQpyZXF1aXJlKERUKQ0KcmVxdWlyZShERVNlcTIpDQpyZXF1aXJlKHJlYWR4bCkNCnJlcXVpcmUoQmlvY1BhcmFsbGVsKQ0KcmVxdWlyZShnZ3Bsb3QyKQ0KcmVxdWlyZShwbG90bHkpDQpyZXF1aXJlKHRocmVlanMpDQpyZXF1aXJlKHNjYWxlcykNCnJlcXVpcmUoZ3JpZEV4dHJhKQ0KcmVxdWlyZShnZ3B1YnIpDQpyZXF1aXJlKGdnZGVuZHJvKQ0KcmVxdWlyZShnZ2ZvcmNlKQ0KDQojIE5PVEU6IG9uIERFU2VxMiBPdXRwdXQ6ICdiYXNlTWVhbicgaXMgdGhlIGF2ZXJhZ2Ugb2YgdGhlIG5vcm1hbGl6ZWQgY291bnQgdmFsdWVzLCANCiMgZGl2aWRlZCBieSB0aGUgc2l6ZSBmYWN0b3JzLCB0YWtlbiBvdmVyIGFsbCBzYW1wbGVzIGluIHRoZSBERVNlcURhdGFTZXQNCmBgYA0KDQojIyBMb2FkIFJOQSBzYW1wbGVzDQpPdXQgb2YgMzAgc2FtcGxlcywgd2Ugc2VsZWN0ZWQgMTcgZm9yIHRoaXMgc3R1ZHkuIFRoZXNlIGFyZSB0aGUgbm9ybWFsIHRpc3N1ZSBzYW1wbGVzIGZvcm0gdGhlIGNvbnRyb2wsIHRoZSBVVkEgYW5kIHRoZSBVVkErU0ZOIHRyZWF0bWVudCBncm91cHMuIG5vcm1hbCB0aXNzdWUgc2FtcGxlcyBmcm9tIHRoZSBVVkJfVUEgZ3JvdXBzIGFzIHdlbGwgYXMgdHVtb3Igc2FtcGxlcyB3ZXJlIGV4Y2x1ZGVkIGZyb20gdGhpcyBhbmFseXNpcy4gQWRkaXRpb25hbGx5LCBvbmUgb2YgdGhlIGNvbnRyb2wgc2FtcGxlcyBhdCBXZWVrIDIgKGJhc2VsaW5lKSB3YXMgcmVtb3ZlZCBhZnRlciBvdXRsaWVyIGFuYWx5c2lzLiAgICANCjcsMjE5IGdlbmVzIHdpdGggemVybyBjb3VudHMgaW4gPiA4MCUgKD4gMTMgb3V0IG9mIDE4KSBvZiBzYW1wbGVzIHdlcmUgcmVtb3ZlZC4gMTcsMjAyIG91dCBvZiAyNCw0MjEgZ2VuZXMgd2VyZSBsZWZ0LiANCiAgICAgICAgIA0KYGBge3IgZGF0YV9ybmEsIHdhcm5pbmcgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9DQojIExvYWQgZGF0YS0tLS0NCmR0MCA8LSBmcmVhZCgiZGF0YS9yZW55aV9kZWR1cF9ybmFzZXFfZGF0YS9mZWF0dXJlc2NvdW50c191dmItc2tpbl9kZWR1cF9yZW55aV8yLTktMjAxOC5jc3YiLA0KICAgICAgICAgICAgIHNraXAgPSAxKQ0KDQojIFJlbW92ZSB1bnVzZWQgY29sdW1ucy0tLS0NCmR0MSA8LSBkdDBbLCBjKDEsIDY6bmNvbChkdDApKSwgd2l0aCA9IEZBTFNFXQ0KDQpjbmFtZXMgPC0gY29sbmFtZXMoZHQxKVstYygxOjIpXQ0KY25hbWVzIDwtIGdzdWIoeCA9IGNuYW1lcywNCiAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLmRlZHVwLmJhbSIsDQogICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICIiKQ0KY29sbmFtZXMoZHQxKVstYygxOjIpXSA8LSBjbmFtZXMNCg0KIyBBVFRFTlRJT04hIEluIHRoaXMgYW5hbHlzaXMsIHdlIHdpbGwgb25seSBleGFtaW5lIGNvbnRyb2xzIGFuZCBTRk4NCiMgQWxzbywgcmVtb3ZlZCBjYW5jZXIgY2VsbCBzYW1wbGVzDQp0bmFtZXMgPC0gc3Vic3RyKHggPSBjb2xuYW1lcyhkdDEpLCANCiAgICAgICAgICAgICAgICAgc3RhcnQgPSAzLA0KICAgICAgICAgICAgICAgICBzdG9wID0gMykNCg0KZ25hbWVzIDwtIHN1YnN0cih4ID0gY29sbmFtZXMoZHQxKSwgDQogICAgICAgICAgICAgICAgIHN0YXJ0ID0gNSwNCiAgICAgICAgICAgICAgICAgc3RvcCA9IDcpDQoNCmR0MSA8LSBkdDFbLCBnbmFtZXMgJWluJSBjKCJpZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAidGgiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNPTiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJTRk4iICkgJg0KICAgICAgICAgICAgIHRuYW1lcyAhPSAidCIsDQogICAgICAgICAgIHdpdGggPSBGQUxTRV0NCiMgMTggc2FtcGxlcyBsZWZ0DQoNCiMgUmVtb3ZlIHNhbXBsZSAnMDJ3X0NPTl8xJyBhcyBhbiBvdXRsaWVyDQojIFNlZSAnc2tpbl91dmJfc2ZuX2V4Y2x1ZGVfY29uMncxX3YxJyBmb3IgZGV0YWlscw0KZHQxIDwtIGR0MVssIGNvbG5hbWVzKGR0MSkgIT0gIjAyd19DT05fMSIsIHdpdGggPSBGQUxTRV0NCg0KIyBSZW1vdmUgZ2VuZXMgd2l0aCB6ZXJvIGNvdW50cyBpbiA+IDgwJSAoPiAxMyBvdXQgb2YgMTcpIG9mIHNhbXBsZXMNCnRtcCA8LSBkdDFbLCAtYygxOjIpXSA9PSAwDQp0bXAgPC0gcm93U3Vtcyh0bXApID4gMTMNCnN1bSh0bXApDQoNCmR0MSA8LSBkcm9wbGV2ZWxzKGR0MVshdG1wLCBdKQ0KbnJvdyhkdDEpDQojIDE3LDIwMiBvdXQgb2YgMjQsNDIxIGdlbmVzIGxlZnQNCg0KZGF0YXRhYmxlKGhlYWQoZHQxLCAxMCksDQogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSwNCiAgICAgICAgICBjbGFzcyA9ICJjZWxsLWJvcmRlciBzdHJpcGUiLA0KICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMCksDQogICAgICAgICAgY2FwdGlvbiA9ICJUYWJsZSAxOiBmaXJzdCAxMCByb3dzIG9mIHRoZSBjb3VudCB0YWJsZSIpDQpgYGANCg0KIyMgVHJhbnNjcmlwdHMgcGVyIGtpbG9iYXNlIG1pbGxpb24gKFRQTSkgbm9ybWFsaXphdGlvbg0KTmV4dCwgd2Ugbm9yYW1pemVkIHRoZSBjb3VudHMuIFRvIGNvbnZlcnQgbnVtYmVyIG9mIGhpdHMgdG8gIHRoZSByZWxhdGl2ZSBhYnVuZGFuZSBvZiBnZW5lcyBpbiBlYWNoIHNhbXBsZSwgd2UgdXNlZCAqKip0cmFuc2NyaXB0cyBwZXIga2lsb2Jhc2UgbWlsbGlvbiAoVFBNKSoqKiBub3JtYWxpemF0aW9uLCB3aGljaCBpcyBhcyBmb2xsb3dpbmcgZm9yIHRoZSBqLXRoIHNhbXBsZTogICAgICAgDQoxLiBub3JtaWxpemUgZm9yIGdlbmUgbGVuZ3RoOiBhW2ksIGpdID0gMSwwMDAqY291bnRbaSwgal0vZ2VuZVtpLCBqXSBsZW5ndGgoYnApICAgICANCjIuIG5vcm1hbGl6ZSBmb3Igc2VxIGRlcHRoIChpLmUuIHRvdGFsIGNvdW50KTogYShpLCBqKS9zdW0oYVssIGpdKSAgICAgDQozLiBtdWx0aXBseSBieSBvbmUgbWlsbGlvbiAgICAgDQpBIHZlcnkgZ29vZCBjb21wYXJpc29uIG9mIG5vcm1hbGl6YXRpb24gdGVjaG5pcXVlcyBjYW4gYmUgZm91bmQgYXQgdGhlIGZvbGxvd2luZyB2aWRlbzogICAgDQpbUlBLTSwgRlBLTSBhbmQgVFBNLCBjbGVhcmx5IGV4cGxhaW5lZF0oaHR0cHM6Ly93d3cucm5hLXNlcWJsb2cuY29tL3Jwa20tZnBrbS1hbmQtdHBtLWNsZWFybHktZXhwbGFpbmVkLykNCiAgICAgDQpBZnRlciB0aGUgbm9ybWFsaXphdGlvbiwgZWFjaCBzYW1wbGUncyB0b3RhbCBpcyAxTToNCiAgICAgDQpgYGB7ciB0cG0sIHdhcm5pbmcgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9DQojIE5vcm1hbGl6ZSBjb3VudHMgdG8gVFBNDQp0bXAgPC0gMTAwMCpkdDFbLCAzOm5jb2woZHQxKV0vZHQxJExlbmd0aA0KdHBtIDwtIGRhdGEudGFibGUoR2VuZWlkID0gZHQxJEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgIExlbmd0aCA9IGR0MSRMZW5ndGgsDQogICAgICAgICAgICAgICAgICBhcHBseSh0bXAsDQogICAgICAgICAgICAgICAgICAgICAgICAyLA0KICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oYSkgew0KICAgICAgICAgICAgICAgICAgICAgICAgICAxMF42KihhL3N1bShhKSkNCiAgICAgICAgICAgICAgICAgICAgICAgIH0pKQ0KY29sU3Vtcyh0cG1bLCAtYygxOjIpXSkNCg0KZGF0YXRhYmxlKGhlYWQodHBtLCAxMCksDQogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSwNCiAgICAgICAgICBjbGFzcyA9ICJjZWxsLWJvcmRlciBzdHJpcGUiLA0KICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMCksDQogICAgICAgICAgY2FwdGlvbiA9ICJUYWJsZSAyOiB0cmFuc2NyaXB0cyBwZXIga2lsb2Jhc2UgbWlsbGlvbiAoVFBNKSBub3JtYWxpemVkIGNvdW50cyIpICU+JSANCiAgZm9ybWF0Um91bmQoY29sdW1ucyA9IDM6bmNvbCh0cG0pLA0KICAgICAgICAgICAgICBkaWdpdHMgPSAyKSAlPiUNCiAgZm9ybWF0U3R5bGUoY29sdW1ucyA9IDM6bmNvbCh0cG0pLA0KICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsDQogICAgICAgICAgICAgIGJhY2tncm91bmRDb2xvciA9IHN0eWxlSW50ZXJ2YWwoY3V0cyA9IGMoMTAsIDEwMCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygid2hpdGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInllbGxvdyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicmVkIikpKQ0KIyBUb3RhbCBUUE0NCnRvdGFsIDwtIHJvd1N1bXModHBtWywgMzpuY29sKHRwbSldKQ0KDQojIFNvcnQgZ2VuZXMgYnkgcmVsYXRpdmUgYWJ1bmRhbmN5DQp0cG0kR2VuZWlkIDwtIGZhY3Rvcih0cG0kR2VuZWlkICwNCiAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHRwbSRHZW5laWRbb3JkZXIodG90YWwsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY3JlYXNpbmcgPSBGQUxTRSldKQ0KYGBgDQoNCkNvbG9yIExlZ2VuZDogICAgDQoqKllFTExPVyoqOiBUTVAgPiAxMCAgICAgIA0KKipSRUQqKjogVE1QID4gMTAwICAgIA0KDQojIFRvcCAxMDAgbW9zdCBhYnVuZGFudCBSTkEgbW9sZWN1bGVzDQpgYGB7ciBtb3N0X2FidW5kYW50fQ0KIyBTZXBhcmF0ZSB0b3AgMTAwIGFidW5kYW50IGdlbmVzDQp0bXAgPC0gZHJvcGxldmVscyh0cG1bR2VuZWlkICVpbiUgbGV2ZWxzKHRwbSRHZW5laWQpWyhucm93KHRwbSkgLSA5OSk6bnJvdyh0cG0pXV0pDQoNCnRtcCA8LSBtZWx0LmRhdGEudGFibGUoZGF0YSA9IHRtcCwNCiAgICAgICAgICAgICAgICAgICAgICAgaWQudmFycyA9IDE6MiwNCiAgICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZS52YXJzID0gMzpuY29sKHRtcCksDQogICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlLm5hbWUgPSAiU2FtcGxlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUubmFtZSA9ICJUUE0iKQ0KDQp0bXAkV2VlayA8LSBzdWJzdHIoeCA9IHRtcCRTYW1wbGUsDQogICAgICAgICAgICAgICAgICAgc3RhcnQgPSAxLA0KICAgICAgICAgICAgICAgICAgIHN0b3AgPSAzKQ0KdG1wJFdlZWsgPC0gZmFjdG9yKHRtcCRXZWVrLA0KICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHVuaXF1ZSh0bXAkV2VlaykpDQoNCg0KdG1wJFRyZWF0bWVudCA8LSBzdWJzdHIoeCA9IHRtcCRTYW1wbGUsDQogICAgICAgICAgICAgICAgICAgICAgICBzdGFydCA9IDUsDQogICAgICAgICAgICAgICAgICAgICAgICBzdG9wID0gNykNCnRtcCRUcmVhdG1lbnQgPC0gZmFjdG9yKHRtcCRUcmVhdG1lbnQsDQogICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJDT04iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlVWQiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTRk4iKSkNCg0KdG1wJFJlcGxpY2EgPC0gc3Vic3RyKHggPSB0bXAkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gOSwNCiAgICAgICAgICAgICAgICAgICAgICBzdG9wID0gOSkNCnRtcCRSZXBsaWNhIDwtIGZhY3Rvcih0bXAkUmVwbGljYSwNCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSAwOjEpDQoNCiMgUGxvdCB0b3AgMTAwIGFidW5kYW50IGdlbmVzDQpwMiA8LSBnZ3Bsb3QodG1wLA0KICAgICAgICAgICAgIGFlcyh4ID0gVFBNLA0KICAgICAgICAgICAgICAgICB5ID0gR2VuZWlkLA0KICAgICAgICAgICAgICAgICBmaWxsID0gVHJlYXRtZW50LA0KICAgICAgICAgICAgICAgICBzaGFwZSA9IFdlZWspKSArDQogICMgZmFjZXRfd3JhcCh+IFNleCwgbnJvdyA9IDEpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMywNCiAgICAgICAgICAgICBhbHBoYSA9IDAuNSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxLA0KICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpDQpnZ3Bsb3RseShwMikNCmBgYA0KDQojIEJvdHRvbSAxMDAgbGVhc3QgYWJ1bmRhbnQgUk5BIG1vbGVjdWxlcw0KYGBge3IgbGVhc3RfYWJ1bmRhbnR9DQp0bXAgPC0gZHJvcGxldmVscyh0cG1bR2VuZWlkICVpbiUgbGV2ZWxzKHRwbSRHZW5laWQpWzE6MTAwXV0pDQoNCnRtcCA8LSBtZWx0LmRhdGEudGFibGUoZGF0YSA9IHRtcCwNCiAgICAgICAgICAgICAgICAgICAgICAgaWQudmFycyA9IDE6MiwNCiAgICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZS52YXJzID0gMzpuY29sKHRtcCksDQogICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlLm5hbWUgPSAiU2FtcGxlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUubmFtZSA9ICJUUE0iKQ0KDQp0bXAkV2VlayA8LSBzdWJzdHIoeCA9IHRtcCRTYW1wbGUsDQogICAgICAgICAgICAgICAgICAgc3RhcnQgPSAxLA0KICAgICAgICAgICAgICAgICAgIHN0b3AgPSAzKQ0KdG1wJFdlZWsgPC0gZmFjdG9yKHRtcCRXZWVrLA0KICAgICAgICAgICAgICAgICAgIGxldmVscyA9IHVuaXF1ZSh0bXAkV2VlaykpDQoNCg0KdG1wJFRyZWF0bWVudCA8LSBzdWJzdHIoeCA9IHRtcCRTYW1wbGUsDQogICAgICAgICAgICAgICAgICAgICAgICBzdGFydCA9IDUsDQogICAgICAgICAgICAgICAgICAgICAgICBzdG9wID0gNykNCnRtcCRUcmVhdG1lbnQgPC0gZmFjdG9yKHRtcCRUcmVhdG1lbnQsDQogICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJDT04iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlVWQiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTRk4iKSkNCg0KdG1wJFJlcGxpY2EgPC0gc3Vic3RyKHggPSB0bXAkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gOSwNCiAgICAgICAgICAgICAgICAgICAgICBzdG9wID0gOSkNCnRtcCRSZXBsaWNhIDwtIGZhY3Rvcih0bXAkUmVwbGljYSwNCiAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSAwOjEpDQoNCiMgUGxvdCB0b3AgMTAwIGFidW5kYW50IGdlbmVzDQpwMyA8LSBnZ3Bsb3QodG1wLA0KICAgICAgICAgICAgIGFlcyh4ID0gVFBNLA0KICAgICAgICAgICAgICAgICB5ID0gR2VuZWlkLA0KICAgICAgICAgICAgICAgICBmaWxsID0gVHJlYXRtZW50LA0KICAgICAgICAgICAgICAgICBzaGFwZSA9IFdlZWspKSArDQogICMgZmFjZXRfd3JhcCh+IFNleCwgbnJvdyA9IDEpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMywNCiAgICAgICAgICAgICBhbHBoYSA9IDAuNSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxLA0KICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIpDQpnZ3Bsb3RseShwMykNCmBgYA0KDQojIE1ldGEgZGF0YQ0KYGBge3IgbWV0YX0NCmRtZXRhIDwtIGRhdGEudGFibGUoU2FtcGxlID0gY29sbmFtZXMoZHQxKVstYygxOjIpXSkNCg0KZG1ldGEkdGltZSA8LSBzdWJzdHIoeCA9IGRtZXRhJFNhbXBsZSwNCiAgICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gMSwNCiAgICAgICAgICAgICAgICAgICAgIHN0b3AgPSAzKQ0KZG1ldGEkdGltZSA8LSBmYWN0b3IoZG1ldGEkdGltZSwNCiAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIjAydyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIxNXciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjV3IikpDQpkbWV0YSRXZWVrIDwtIGZhY3RvcihkbWV0YSR0aW1lLA0KICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiMDJ3IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjE1dyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyNXciKSwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIldlZWsgMiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXZWVrIDE1IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIldlZWsgMjUiKSkNCg0KZG1ldGEkdHJ0IDwtIHN1YnN0cih4ID0gZG1ldGEkU2FtcGxlLA0KICAgICAgICAgICAgICAgICAgICBzdGFydCA9IDUsDQogICAgICAgICAgICAgICAgICAgIHN0b3AgPSA3KQ0KZG1ldGEkdHJ0IDwtIGZhY3RvcihkbWV0YSR0cnQsDQogICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkNPTiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJVVkIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTRk4iKSkNCmRtZXRhJFRyZWF0bWVudCA8LSBmYWN0b3IoZG1ldGEkdHJ0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJDT04iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU0ZOIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIk5lZ2F0aXZlIENvbnRyb2wiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQb3NpdGl2ZSBDb250cm9sIChVVkIpIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU3VsZm9yYXBoYW5lIChTRk4pIikpDQoNCmRtZXRhJFJlcGxpY2EgPC0gc3Vic3RyKHggPSBkbWV0YSRTYW1wbGUsDQogICAgICAgICAgICAgICAgICAgICAgICBzdGFydCA9IDksDQogICAgICAgICAgICAgICAgICAgICAgICBzdG9wID0gOSkNCmRtZXRhJFJlcGxpY2EgPC0gZmFjdG9yKGRtZXRhJFJlcGxpY2EsDQogICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSAwOjEpDQoNCmRhdGF0YWJsZShkbWV0YSwNCiAgICAgICAgICByb3duYW1lcyA9IEZBTFNFLA0KICAgICAgICAgIGNsYXNzID0gImNlbGwtYm9yZGVyIHN0cmlwZSIsDQogICAgICAgICAgb3B0aW9ucyA9IGxpc3QocGFnZUxlbmd0aCA9IG5yb3coZG1ldGEpKSkNCmBgYA0KDQojIFBDQSBvZiBUUE0NCk5PVEU6IHRoZSBkaXN0cmlidXRpb25zIGFyZSBza2V3ZWQuIFRvIG1ha2UgdGhlbSBzeW1tZXRyaWMsIGxvZyB0cmFuc2Zvcm1hdGlvbiBpcyBvZnRlbiBhcHBsaWVkLiBIb3dldmVyLCB0aGVyZSBpcyBhbiBpc3N1ZSBvZiB6ZXJvcy4gSW4gdGhpcyBpbnN0YW5jZSwgd2UgYWRkZWQgYSBzbWFsbCB2YWx1ZXMgKioqbGFtYmRhW2ldKioqIGVxdWFsIHRvIDEvMTAgb2YgdGhlIHNtYWxsZXN0IG5vbi16ZXJvIHZhbHVlIG9mICppKi10aCBnZW5lLiANCmBgYHtyIHBjYX0NCmRtLnRwbSA8LSBhcy5tYXRyaXgodHBtWywgLWMoMToyKSwgd2l0aCA9IEZBTFNFXSkNCnJvd25hbWVzKGRtLnRwbSkgPC0gdHBtJEdlbmVpZA0KDQojICMgUmVtb3ZlIDAyd19DT05fMSBzYW1wbGUgYW5kIHJlZG8gUENBDQojIGRtLnRwbSA8LSBkbS50cG1bLCBjb2xuYW1lcyhkbS50cG0pICE9ICIwMndfQ09OXzEiXQ0KIyBkbWV0YSA8LSBkbWV0YVtkbWV0YSRTYW1wbGUgIT0gIjAyd19DT05fMSIsIF0NCg0KIyBBZGQgbGFtYmRhcyB0byBhbGwgdmFsdWVzLCB0aGVuIHRha2UgYSBsb2cNCmRtLmx0cG0gPC0gdChhcHBseShYID0gZG0udHBtLA0KICAgICAgICAgICAgICAgICAgICAgIE1BUkdJTiA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgRlVOID0gZnVuY3Rpb24oYSkgew0KICAgICAgICAgICAgICAgICAgICAgICAgbGFtYmRhIDwtIG1pbihhW2EgPiAwXSkvMTANCiAgICAgICAgICAgICAgICAgICAgICAgIGxvZyhhICsgbGFtYmRhKQ0KICAgICAgICAgICAgICAgICAgICAgIH0pKQ0KDQojIFBDQS0tLS0NCm0xIDwtIHByY29tcCh0KGRtLmx0cG0pLA0KICAgICAgICAgICAgIGNlbnRlciA9IFRSVUUsDQogICAgICAgICAgICAgc2NhbGUuID0gVFJVRSkNCg0KczEgPC0gc3VtbWFyeShtMSkNCnMxDQpgYGANCg0KIyBQYXJldG8gY2hhcnQgb2YgdmFyaWFuY2UgZXhwbGFpbmVkIGJ5IHByaW5jaXBhbCBjb21wb25lbnRzDQpgYGB7ciBwY2FfdmFyX3Bsb3R9DQppbXAgPC0gZGF0YS50YWJsZShQQyA9IGNvbG5hbWVzKHMxJGltcG9ydGFuY2UpLA0KICAgICAgICAgICAgICAgICAgVmFyaWFuY2UgPSAxMDAqczEkaW1wb3J0YW5jZVsyLCBdLA0KICAgICAgICAgICAgICAgICAgQ3VtdWxhdGl2ZSA9IDEwMCpzMSRpbXBvcnRhbmNlWzMsIF0pDQppbXAkUEMgPC0gZmFjdG9yKGltcCRQQywNCiAgICAgICAgICAgICAgICAgbGV2ZWxzID0gaW1wJFBDKQ0KcDEgPC0gZ2dwbG90KGltcCwNCiAgICAgICAgICAgICBhZXMoeCA9IFBDLA0KICAgICAgICAgICAgICAgICB5ID0gVmFyaWFuY2UpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLA0KICAgICAgICAgICBmaWxsID0gImdyZXkiLA0KICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gcmVzY2FsZShDdW11bGF0aXZlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvID0gYyhtaW4oQ3VtdWxhdGl2ZSkqbWF4KGltcCRWYXJpYW5jZSkvMTAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXgoaW1wJFZhcmlhbmNlKSkpLA0KICAgICAgICAgICAgICAgIGdyb3VwID0gcmVwKDEsIG5yb3coaW1wKSkpKSArDQogIGdlb21fcG9pbnQoYWVzKHkgPSByZXNjYWxlKEN1bXVsYXRpdmUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvID0gYyhtaW4oQ3VtdWxhdGl2ZSkqbWF4KGltcCRWYXJpYW5jZSkvMTAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4KGltcCRWYXJpYW5jZSkpKSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKCIlIFZhcmlhbmNlIEV4cGxhaW5lZCIsDQogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoZnJvbSA9IDAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvID0gbWF4KGltcCRWYXJpYW5jZSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gNSksDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBwYXN0ZShzZXEoZnJvbSA9IDAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvID0gbWF4KGltcCRWYXJpYW5jZSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSA1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcCA9ICIiKSwNCiAgICAgICAgICAgICAgICAgICAgIHNlYy5heGlzID0gc2VjX2F4aXModHJhbnMgPSB+LiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICIlIEN1bXVsYXRpdmUgVmFyaWFuY2UiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoZnJvbSA9IDAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG8gPSBtYXgoaW1wJFZhcmlhbmNlKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGgub3V0ID0gNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHBhc3RlKHNlcShmcm9tID0gMCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0byA9IDEwMCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZW5ndGgub3V0ID0gNSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VwID0gIiIpKSkgKw0KICBzY2FsZV94X2Rpc2NyZXRlKCIiKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMSkpDQoNCiMgU2F2ZSBmb3IgcHVibGljYXRpb24NCnRpZmYoZmlsZW5hbWUgPSAidG1wL3BjYV9wYXJldG8udGlmZiIsDQogICAgIGhlaWdodCA9IDYsDQogICAgIHdpZHRoID0gOCwNCiAgICAgdW5pdHMgPSAnaW4nLA0KICAgICByZXMgPSA2MDAsDQogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikNCnByaW50KHAxKQ0KZ3JhcGhpY3Mub2ZmKCkNCg0KcHJpbnQocDEpDQpgYGANCg0KIyBGaXJzdCAzIHByaW5jaXBhbCBjb21wb25lbnRzLCBwYWlyd2lzZQ0KYGBge3IgcGNhX3Bsb3RzfQ0KIyBCaXBsb3Qgd2hpbGUga2VlcCBvbmx5IHRoZSBtb3N0IGltcG9ydGFudCB2YXJpYWJsZXMgKEphdmllciktLS0tDQojIFNlbGVjdCBQQy1zIHRvIHBsaW90IChQQzEgJiBQQzIpDQpjaG9pY2VzIDwtIGMoMTozKQ0KDQojIFNjb3JlcywgaS5lLiBwb2ludHMgKGRmLnUpDQpkdC5zY3IgPC0gZGF0YS50YWJsZShtMSR4WywgY2hvaWNlc10pDQojIEFkZCBncm91cGluZyB2YXJpYWJsZXMNCmR0LnNjciR0cnQgPC0gZG1ldGEkdHJ0DQpkdC5zY3IkdGltZSA8LSBkbWV0YSR0aW1lDQpkdC5zY3Ikc2FtcGxlIDwtIGRtZXRhJFNhbXBsZQ0KDQojIExvYWRpbmdzLCBpLmUuIGFycm93cyAoZGYudikNCmR0LnJvdCA8LSBhcy5kYXRhLmZyYW1lKG0xJHJvdGF0aW9uWywgY2hvaWNlc10pDQpkdC5yb3QkZmVhdCA8LSByb3duYW1lcyhkdC5yb3QpDQpkdC5yb3QgPC0gZGF0YS50YWJsZShkdC5yb3QpDQoNCiMgQXhpcyBsYWJlbHMNCnUuYXhpcy5sYWJzIDwtIHBhc3RlKGNvbG5hbWVzKGR0LnJvdClbY2hvaWNlc10sIA0KICAgICAgICAgICAgICAgICAgICAgc3ByaW50ZignKCUwLjFmJSUgZXhwbGFpbmVkIHZhci4pJywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEwMCptMSRzZGV2W2Nob2ljZXNdXjIvc3VtKG0xJHNkZXZeMikpKQ0KDQpwMSA8LSBnZ3Bsb3QoZGF0YSA9IGR0LnNjciwNCiAgICAgICAgICAgICBhZXMoeCA9IFBDMSwNCiAgICAgICAgICAgICAgICAgeSA9IFBDMiwNCiAgICAgICAgICAgICAgICAgY29sb3IgPSB0cnQsDQogICAgICAgICAgICAgICAgIHNoYXBlID0gdGltZSkpICsNCiAgZ2VvbV9wb2ludChzaXplID0gNCwNCiAgICAgICAgICAgICBhbHBoYSA9IDAuNSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXModS5heGlzLmxhYnNbMV0pICsNCiAgc2NhbGVfeV9jb250aW51b3VzKHUuYXhpcy5sYWJzWzJdKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCmdncGxvdGx5KHAxKQ0KDQpwMiA8LSBnZ3Bsb3QoZGF0YSA9IGR0LnNjciwNCiAgICAgICAgICAgICBhZXMoeCA9IFBDMSwNCiAgICAgICAgICAgICAgICAgeSA9IFBDMywNCiAgICAgICAgICAgICAgICAgY29sb3IgPSB0cnQsDQogICAgICAgICAgICAgICAgIHNoYXBlID0gdGltZSkpICsNCiAgZ2VvbV9wb2ludChzaXplID0gNCwNCiAgICAgICAgICAgICBhbHBoYSA9IDAuNSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXModS5heGlzLmxhYnNbMV0pICsNCiAgc2NhbGVfeV9jb250aW51b3VzKHUuYXhpcy5sYWJzWzNdKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCmdncGxvdGx5KHAyKQ0KDQpwMyA8LSBnZ3Bsb3QoZGF0YSA9IGR0LnNjciwNCiAgICAgICAgICAgICBhZXMoeCA9IFBDMiwNCiAgICAgICAgICAgICAgICAgeSA9IFBDMywNCiAgICAgICAgICAgICAgICAgY29sb3IgPSB0cnQsDQogICAgICAgICAgICAgICAgIHNoYXBlID0gdGltZSkpICsNCiAgZ2VvbV9wb2ludChzaXplID0gNCwNCiAgICAgICAgICAgICBhbHBoYSA9IDAuNSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXModS5heGlzLmxhYnNbMl0pICsNCiAgc2NhbGVfeV9jb250aW51b3VzKHUuYXhpcy5sYWJzWzNdKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCmdncGxvdGx5KHAzKQ0KDQojIExlZ2VuZCBvbmx5DQp0bXAgPC0gZ2dwbG90KGRhdGEgPSBkdC5zY3IsDQogICAgICAgICAgICAgYWVzKHggPSBQQzEsDQogICAgICAgICAgICAgICAgIHkgPSBQQzIsDQogICAgICAgICAgICAgICAgIGNvbG9yID0gdHJ0LA0KICAgICAgICAgICAgICAgICBzaGFwZSA9IHRpbWUpKSArDQogIGdlb21fcG9pbnQoKSArDQogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKCJUcmVhdG1lbnQiKSArDQogIHNjYWxlX3NoYXBlX2Rpc2NyZXRlKCJXZWVrIikNCnA0IDwtIGFzX2dncGxvdChnZXRfbGVnZW5kKHRtcCkpDQoNCiMgU2F2ZSBmb3IgcHVibGljYXRpb24NCnRpZmYoZmlsZW5hbWUgPSAidG1wL3BjYS50aWZmIiwNCiAgICAgaGVpZ2h0ID0gNywNCiAgICAgd2lkdGggPSA5LA0KICAgICB1bml0cyA9ICdpbicsDQogICAgIHJlcyA9IDYwMCwNCiAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQ0KZ3JpZC5hcnJhbmdlKHAxLCBwMiwgcDMsIHA0LCANCiAgICAgICAgICAgICBucm93ID0gMikNCmdyYXBoaWNzLm9mZigpDQpgYGANCg0KIyBGaXJzdCAzIHByaW5jaXBhbCBjb21wb25lbnRzLCAzRA0KYGBge3IgcGNhXzNkLCBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDEwfQ0Kc2NhdHRlcnBsb3QzanMoeCA9IGR0LnNjciRQQzEsIA0KICAgICAgICAgICAgICAgeSA9IGR0LnNjciRQQzIsIA0KICAgICAgICAgICAgICAgeiA9IGR0LnNjciRQQzMsIA0KICAgICAgICAgICAgICAgY29sb3IgPSBhcy5udW1lcmljKGR0LnNjciR0cnQpLA0KICAgICAgICAgICAgICAgcmVuZGVyZXIgPSAiYXV0byIsDQogICAgICAgICAgICAgICBwY2ggPSBkdC5zY3Ikc2FtcGxlLA0KICAgICAgICAgICAgICAgc2l6ZSA9IDAuMSkNCmBgYA0KDQojIERpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuYWx5c2lzIChERVNlcTIgcGlwZWxpbmUpDQpTb3VyY2VzOiAgICANCjEuIFtBbmFseXppbmcgUk5BLXNlcSBkYXRhIHdpdGggREVTZXEyOkludGVyYWN0aW9uc10oaHR0cHM6Ly93d3cuYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9kZXZlbC9iaW9jL3ZpZ25ldHRlcy9ERVNlcTIvaW5zdC9kb2MvREVTZXEyLmh0bWwjaW50ZXJhY3Rpb25zKSAgICAgDQoyLiBbQmlvY29uZHVjdG9yIFF1ZXN0aW9uOiBERVNlcTIgdGltZSBzZXJpZXMgYW5hbHlzaXNdKGh0dHBzOi8vc3VwcG9ydC5iaW9jb25kdWN0b3Iub3JnL3AvOTc0MzAvKSAgICAgIA0KV2UgYXJlIHRlc3RpbmcgYSBtb2RlbCB3aXRoIHRpbWUqdHJlYXRtZW50IGludGVyYWN0aW9uLiBUaGUgaWRlYSBoZXJlIGlzIHRvIGZpbmQgZ2VuZXMgd2l0aCBzaWduaWZpY2FudCBpbnRlcmFjdGlvbiB0ZXJtLiBUaGF0IHdvdWxkIHN1Z2dlc3QgdGhhdCB0aGUgZ2VuZSBleHByZXNzaW9uZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgdHJlYXRtZW50cyBkZXBlbmRlZCBvbiB0aW1lLiBUSGVyZSBhcmUgc2V2ZXJhbCBwb3NzaWJsZSBzY2VuYXJpb3M6ICAgIA0KYS4gTm8gZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBuZWdhdGl2ZSBjb250cm9sIGFuZCB0aGUgcG9zaXRpdmUgY29udHJvbCBncm91cHMgYXQgYmFzZWxpbmUsIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgYXQgdGhlIGxhdGVyIHRpbWUgcG9pbnQuIFRoaXMgd2lsbCBzaG93IHRoZSBlZmZlY3Qgb2YgdGhlIGRpc2Vhc2UgKFVWQiByYWRpYXRpb24sIGluIHRoaXMgY2FzZSkuICAgICANCmIuIFNpZ25pZmljYW50IGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgY29udHJvbCBncm91cHMgYXQgYmFzZWxpbmUsIG5vIGRpZmZlcmVuY2UgYXQgdGhlIGxhdGVyIHRpbWUgcG9pbnQuIFNhbWUgYXMgKGEpIGFib3ZlLiAgICAgDQpjLiBEaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSBwb3NpdGl2ZSBjb250cm9sIGFuZCB0aGUgU0ZOLXRyZWF0ZWQgZ3JvdXBzLiBIZXJlLCB3ZSBhcmUgaW50ZXJlc3RlZCBpbiB0aGUgcmV2ZXJzYWwgb2YgVVZCIGVmZmVjdC4gQWdhaW4sIHRoZSBpbnRlcmFjdGlvbiB0ZXJtIHdpbGwgbmVlZCB0byBiZSBzaWduaWZpY2FudCBmb3IgdGhlIHJlYXNvbnMgZGVzY3JpYmVkIGFib3ZlLiAgICAgIA0KDQpgYGB7ciBkZXNlcTJ9DQojIFJlbGV2ZWw6IG1ha2UgYWxsIGNvbXBhcmlzb25zIHdpdGggdGhlIHBvc2l0aXZlIGNvbnRyb2wgKFVWQikNCmRtZXRhJHRydCA8LSBmYWN0b3IoZG1ldGEkdHJ0LA0KICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJVVkIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDT04iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTRk4iKSkNCg0KZHRtPC0gYXMubWF0cml4KGR0MVssIGRtZXRhJFNhbXBsZSwNCiAgICAgICAgICAgICAgICAgICAgd2l0aCA9IEZBTFNFXSkNCnJvd25hbWVzKGR0bSkgPC0gZHQxJEdlbmVpZA0KDQpkZHMgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGEgPSBkdG0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IGRtZXRhLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfiB0aW1lICsgdHJ0ICsgdGltZTp0cnQpDQojIElmIGFsbCBzYW1wbGVzIGNvbnRhaW4gemVyb3MsIGdlb21ldHJpYyBtZWFucyBjYW5ub3QgYmUNCiMgZXN0aW1hdGVkLiBDaGFuZ2UgZGVmYXVsdCAndHlwZSA9ICJyYXRpbyInIHRvICd0eXBlID0gInBvc2NvdW50cyInLg0KIyBUeXBlICc/REVTZXEyOjplc3RpbWF0ZVNpemVGYWN0b3JzJyBmb3IgbW9yZSBkZXRhaWxzLg0KZGRzIDwtIGVzdGltYXRlU2l6ZUZhY3RvcnMob2JqZWN0ID0gZGRzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJwb3Njb3VudHMiKQ0KDQojIFJ1biBERVNlcS0tLS0NCmRkcyA8LSBERVNlcShvYmplY3QgPSBkZHMsDQogICAgICAgICAgICAgIyB0ZXN0ID0gIkxSVCIsDQogICAgICAgICAgICAgIyByZWR1Y2VkID0gfiB0aW1lICsgdHJ0LA0KICAgICAgICAgICAgIGZpdFR5cGUgPSAibG9jYWwiLA0KICAgICAgICAgICAgIHNmVHlwZSA9ICJyYXRpbyIsDQogICAgICAgICAgICAgcGFyYWxsZWwgPSBGQUxTRSkNCg0KIyBOT1RFIChmcm9tIERFU2VxIGhlbHAgZmlsZSwgc2VjdGlvbiBWYWx1ZSk6DQojIEEgREVTZXFEYXRhU2V0IG9iamVjdCB3aXRoIHJlc3VsdHMgc3RvcmVkIGFzIG1ldGFkYXRhIGNvbHVtbnMuIA0KIyBUaGVzZSByZXN1bHRzIHNob3VsZCBhY2Nlc3NlZCBieSBjYWxsaW5nIHRoZSByZXN1bHRzIGZ1bmN0aW9uLiANCiMgQnkgZGVmYXVsdCB0aGlzIHdpbGwgcmV0dXJuIHRoZSBsb2cyIGZvbGQgY2hhbmdlcyBhbmQgcC12YWx1ZXMNCiMgZm9yIHRoZSBsYXN0IHZhcmlhYmxlIGluIHRoZSBkZXNpZ24gZm9ybXVsYS4gDQojIFNlZSByZXN1bHRzIGZvciBob3cgdG8gYWNjZXNzIHJlc3VsdHMgZm9yIG90aGVyIHZhcmlhYmxlcy4NCiMgSW4gdGhpcyBjYXNlLCB0aGUgbGFzdCB0ZXJtIGlzIHRoZSBpbnRlcmFjdGlvbiB0ZXJtIHRydDp0aW1lDQoNCiMgTk9URTogDQojIExpa2VsaWhvb2QgcmF0aW8gdGVzdCAoTFJUKSAoY2hpLXNxdWFyZWQgdGVzdCkgZm9yIEdMTSB3aWxsIG9ubHkgcmV0dXJuIA0KIyB0aGUgcmVzdWx0cyBmb3IgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgZnVsbCBhbmQgdGhlIHJlZHVjZWQgbW9kZWwNCg0KcmVzdWx0c05hbWVzKGRkcykNCg0KIyBNb2RlbCBtYXRyaXgNCm1tMSA8LSBtb2RlbC5tYXRyaXgofiB0aW1lICsgdHJ0ICsgdGltZTp0cnQsIGRtZXRhKQ0KbW0xDQoNCmhlYWQobWNvbHMoZGRzKSkNCmBgYA0KDQojIFJlc3VsdHMNCiMjIEVmZmVjdCBvZiBVVkIgYXQgV2VlayAyDQpgYGB7ciBkZXNlcTJfcmVzdWx0c193ZWVrMl9jb25fdXZifQ0KIyByZXNfY29uX3V2Yl93ZWVrMiA8LSByZXN1bHRzKGRkcywNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdCA9IGMoMCwwLDAsMSwwLDAsMCwwLDApLA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4xKQ0KIyBTQU1FIEFTOg0KcmVzX2Nvbl91dmJfd2VlazIgPC0gcmVzdWx0cyhkZHMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAidHJ0X0NPTl92c19VVkIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMSkNCnJlc19jb25fdXZiX3dlZWsyIDwtIHJlc19jb25fdXZiX3dlZWsyW29yZGVyKHJlc19jb25fdXZiX3dlZWsyJHBhZGosDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWNyZWFzaW5nID0gRkFMU0UpLF0NCnN1bW1hcnkocmVzX2Nvbl91dmJfd2VlazIpDQoNCiMgSG93IG1hbnkgYWRqdXN0ZWQgcC12YWx1ZXMgd2VyZSBsZXNzIHRoYW4gMC4wNT8NCnN1bShyZXNfY29uX3V2Yl93ZWVrMiRwYWRqIDwgMC4xLCANCiAgICBuYS5ybSA9IFRSVUUpDQoNCiMgTUEgcGxvdA0KIyBTYXZlIGZvciBwdWJsaWNhdGlvbg0KdGlmZihmaWxlbmFtZSA9ICJ0bXAvbWFfdzJfY29uX3V2Yi50aWZmIiwNCiAgICAgaGVpZ2h0ID0gNiwNCiAgICAgd2lkdGggPSA3LA0KICAgICB1bml0cyA9ICdpbicsDQogICAgIHJlcyA9IDYwMCwNCiAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQ0KcGxvdE1BKHJlc19jb25fdXZiX3dlZWsyLA0KICAgICAgICAgICAgIG1haW4gPSAiQ29udHJvbCB2cy4gVVZCIGF0IFdlZWsgMiIsDQogICAgICAgICAgICAgYWxwaGEgPSAwLjgpDQpncmFwaGljcy5vZmYoKQ0KDQpwbG90TUEocmVzX2Nvbl91dmJfd2VlazIsDQogICAgICAgICAgICAgbWFpbiA9ICJDb250cm9sIHZzLiBVVkIgYXQgV2VlayAyIiwNCiAgICAgICAgICAgICBhbHBoYSA9IDAuOCkNCmBgYA0KDQojIyBQcm90ZWN0aXZlIGVmZmVjdCBvZiBTRk4gYXQgV2VlayAyDQpgYGB7ciBkZXNlcTJfcmVzdWx0c193ZWVrMl9zZm5fdXZifQ0KIyByZXNfc2ZuX3V2Yl93ZWVrMiA8LSByZXN1bHRzKGRkcywNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdCA9IGMoMCwwLDAsMCwxLDAsMCwwLDApLA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4xKQ0KIyBTQU1FIEFTOw0KcmVzX3Nmbl91dmJfd2VlazIgPC0gcmVzdWx0cyhkZHMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAidHJ0X1NGTl92c19VVkIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMSkNCnJlc19zZm5fdXZiX3dlZWsyIDwtIHJlc19zZm5fdXZiX3dlZWsyW29yZGVyKHJlc19zZm5fdXZiX3dlZWsyJHBhZGosDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWNyZWFzaW5nID0gRkFMU0UpLF0NCnN1bW1hcnkocmVzX3Nmbl91dmJfd2VlazIpDQoNCiMgSG93IG1hbnkgYWRqdXN0ZWQgcC12YWx1ZXMgd2VyZSBsZXNzIHRoYW4gMC4wNT8NCnN1bShyZXNfc2ZuX3V2Yl93ZWVrMiRwYWRqIDwgMC4xLCANCiAgICBuYS5ybSA9IFRSVUUpDQoNCiMgTUEgcGxvdA0KIyBTYXZlIGZvciBwdWJsaWNhdGlvbg0KdGlmZihmaWxlbmFtZSA9ICJ0bXAvbWFfdzJfc2ZuX3V2Yi50aWZmIiwNCiAgICAgaGVpZ2h0ID0gNiwNCiAgICAgd2lkdGggPSA3LA0KICAgICB1bml0cyA9ICdpbicsDQogICAgIHJlcyA9IDYwMCwNCiAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQ0KcHJpbnQocGxvdE1BKHJlc19zZm5fdXZiX3dlZWsyLA0KICAgICAgICAgICAgIG1haW4gPSAiVVZCK1NGTiB2cyBVVkIgYXQgV2VlayAyIiwNCiAgICAgICAgICAgICBhbHBoYSA9IDAuOCkpDQpncmFwaGljcy5vZmYoKQ0KDQpwcmludChwbG90TUEocmVzX3Nmbl91dmJfd2VlazIsDQogICAgICAgICAgICAgbWFpbiA9ICJVVkIrU0ZOIHZzIFVWQiBhdCBXZWVrIDIiLA0KICAgICAgICAgICAgIGFscGhhID0gMC44KSkNCmBgYA0KDQojIyBHZW5lcyB0aGF0IHdlcmUgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnRpYXRlZCBhdCBib3RoIGNvbXBhcmlzb25zIGF0IFdlZWsgMg0KYGBge3Igc2lnbl93Mn0NCmxnZW5lLncyLmNvbiA8LSB1bmlxdWUocmVzX2Nvbl91dmJfd2VlazJAcm93bmFtZXNbcmVzX2Nvbl91dmJfd2VlazIkcGFkaiA8IDAuMV0pDQpsZ2VuZS53Mi5zZm4gPC0gdW5pcXVlKHJlc19zZm5fdXZiX3dlZWsyQHJvd25hbWVzW3Jlc19zZm5fdXZiX3dlZWsyJHBhZGogPCAwLjFdKQ0KbGdlbmUudzIgPC0gbGdlbmUudzIuY29uW2xnZW5lLncyLmNvbiAlaW4lIGxnZW5lLncyLnNmbl0NCmxnZW5lLncyIDwtIGxnZW5lLncyIFshaXMubmEobGdlbmUudzIgKV0NCmxnZW5lLncyDQpgYGANCg0KUGxvdCBvZiBERVNlcS1ub3JtYWxpemVkY291bnRzIG9mIGdlbmVzIHNpZ25pZmljYW50IGluIGJvdGggY29tcGFyaXNvbnMgYXQgV2VlayAyOiAgIA0KDQpgYGB7ciBkZXNlcTJfdzJzaWduX2Rlc2Vxbm9ybX0NCiMgR2V0IHRoZSBERVNlcS1ub3JtYWxpemUgY291bnRzDQpkcDEgPC0gbGlzdCgpDQpmb3IgKGkgaW4gMTpsZW5ndGgobGdlbmUudzIpKSB7DQogIG91dCA8LSBwbG90Q291bnRzKGRkcywgDQogICAgICAgICAgICAgICAgICAgIGdlbmUgPSBsZ2VuZS53MltbaV1dLA0KICAgICAgICAgICAgICAgICAgICBpbnRncm91cCA9IGMoInRydCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidGltZSIpLA0KICAgICAgICAgICAgICAgICAgICByZXR1cm5EYXRhID0gVFJVRSkNCiAgZHAxW1tpXV0gPC0gZGF0YS50YWJsZShHZW5laWQgPSBsZ2VuZS53MltbaV1dLA0KICAgICAgICAgICAgICAgICAgICAgICAgIFNhbXBsZSA9IHJvd25hbWVzKG91dCksDQogICAgICAgICAgICAgICAgICAgICAgICAgb3V0KQ0KfQ0KZHAxIDwtIHJiaW5kbGlzdChkcDEpDQpkcDEkdHJ0IDwtIGZhY3RvcihkcDEkdHJ0LA0KICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQ09OIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlVWQiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTRk4iKSkNCmRwMSR0aW1lIDwtIGZhY3RvcihkcDEkdGltZSwNCiAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCIwMnciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjE1dyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjV3IiksDQogICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiV2VlayAyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXZWVrIDE1IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXZWVrIDI1IikpDQpkcDEkR2VuZWlkIDwtIGZhY3RvcihkcDEkR2VuZWlkLA0KICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gbGdlbmUudzIpDQpkcDFbLCBtdSA6PSBtZWFuKGNvdW50LA0KICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpLA0KICAgIGJ5ID0gYygiR2VuZWlkIiwNCiAgICAgICAgICAgInRydCIsDQogICAgICAgICAgICJ0aW1lIildDQpkbXUgPC0gdW5pcXVlKGRwMVssIC1jKCJTYW1wbGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAiY291bnQiKV0pDQpkYXRhdGFibGUoaGVhZChkbXUpLA0KICAgICAgICAgIHJvd25hbWVzID0gRkFMU0UsDQogICAgICAgICAgY2xhc3MgPSAiY2VsbC1ib3JkZXIgc3RyaXBlIikgJT4lIA0KICBmb3JtYXRSb3VuZChjb2x1bW5zID0gNCwNCiAgICAgICAgICAgICAgZGlnaXRzID0gMikNCmBgYA0KDQpgYGB7ciBkZXNlcTJfdzJzaWduX2Rlc2Vxbm9ybV93Ml91cF9kbiwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSA4fQ0KZG11LncyIDwtIGRtdVt0aW1lID09ICJXZWVrIDIiLCBdDQpkbXUudzJbLCB1cC5kbiA6PSAobXVbdHJ0ID09ICJVVkIiXSA+IG11W3RydCA9PSAiQ09OIl0pICYNCiAgICAgICAgICAgICAgIChtdVt0cnQgPT0gIlVWQiJdID4gbXVbdHJ0ID09ICJTRk4iXSksDQogICAgICAgYnkgPSBHZW5laWRdDQpwMSA8LSBnZ3Bsb3QoZG11LncyW3VwLmRuID09IFRSVUUsIF0sDQogICAgICAgICAgICAgYWVzKHggPSB0cnQsDQogICAgICAgICAgICAgICAgIHkgPSBtdSwNCiAgICAgICAgICAgICAgICAgZ3JvdXAgPSBHZW5laWQsDQogICAgICAgICAgICAgICAgIGZpbGwgPSB0cnQpKSArDQogICAgICAgIGZhY2V0X3dyYXAofiBHZW5laWQsDQogICAgICAgICAgICAgICAgICAgc2NhbGUgPSAiZnJlZV95IikgKw0KICAgICAgICBnZW9tX2xpbmUocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjUpKSArDQogICAgICAgIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjUpLA0KICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMjEsDQogICAgICAgICAgICAgICAgICAgc2l6ZSA9IDMsDQogICAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siKSArDQogICAgICAgIHNjYWxlX3hfZGlzY3JldGUoIiIpICsNCiAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKCJEaWZmZXJlbnRpYWxseSBFeHByZXNzZWQgR2VuZXMgYXQgV2VlayAyIikgKw0KICAgICAgICBzY2FsZV9maWxsX2Rpc2NyZXRlKCJUcmVhdG1lbnQiKSArDQogICAgICAgIGdndGl0bGUoIkdlbmVzIFVwcmVndWxhdGVkIGJ5IFVWQiIpDQp0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxKSkNCg0KdGlmZihmaWxlbmFtZSA9ICJ0bXAvdzJfdXBfZG4udGlmZiIsDQogICAgIGhlaWdodCA9IDYsDQogICAgIHdpZHRoID0gOCwNCiAgICAgdW5pdHMgPSAnaW4nLA0KICAgICByZXMgPSAzMDAsDQogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikNCnByaW50KHAxKQ0KZ3JhcGhpY3Mub2ZmKCkNCg0KcHJpbnQocDEpDQpgYGANCg0KIyMgRGlkIGRvd24tdXAtZG93biB0cmVuZCBwZXJzaXN0Pw0KYGBge3IgZGVzZXEyX3cyc2lnbl9kZXNlcW5vcm1fcGxvdF9hbGxfdXBfZG4sIGZpZy5oZWlnaHQgPSAxMCwgZmlnLndpZHRoID0gMTJ9DQpkcDEudG1wIDwtIGRwMVtkcDEkR2VuZWlkICVpbiUgdW5pcXVlKGRtdS53MiRHZW5laWRbZG11LncyJHVwLmRuXSksIF0NCmRtdS50bXAgPC0gZG11W2RtdSRHZW5laWQgJWluJSB1bmlxdWUoZG11LncyJEdlbmVpZFtkbXUudzIkdXAuZG5dKSwgXQ0KcDEgPC0gZ2dwbG90KGRwMS50bXAsDQogICAgICAgICAgICAgYWVzKHggPSB0aW1lLA0KICAgICAgICAgICAgICAgICB5ID0gY291bnQsDQogICAgICAgICAgICAgICAgIGdyb3VwID0gdHJ0LA0KICAgICAgICAgICAgICAgICBmaWxsID0gdHJ0KSkgKw0KICBmYWNldF93cmFwKH4gR2VuZWlkLA0KICAgICAgICAgICAgIHNjYWxlID0gImZyZWVfeSIpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICBzaXplID0gNSwNCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBkbXUudG1wLA0KICAgICAgICAgICAgYWVzKHggPSB0aW1lLA0KICAgICAgICAgICAgICAgIHkgPSBtdSwNCiAgICAgICAgICAgICAgICBncm91cCA9IHRydCwNCiAgICAgICAgICAgICAgICBjb2xvdXIgPSB0cnQpLA0KICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjUpLA0KICAgICAgICAgICAgYWxwaGEgPSAwLjUsDQogICAgICAgICAgICBzaXplID0gMikgKw0KICBzY2FsZV94X2Rpc2NyZXRlKCIiKSArDQogIHNjYWxlX3lfY29udGludW91cygiREVTZXEtTm9ybWFsaXplZCBDb3VudHMiKSArDQogIHNjYWxlX2ZpbGxfZGlzY3JldGUoIlRyZWF0bWVudCIpDQpwcmludChwMSkNCmBgYA0KDQpgYGB7ciBkZXNlcTJfdzJzaWduX2Rlc2Vxbm9ybV93Ml9kbl91cCwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSA4fQ0KZG11LncyWywgZG4udXAgOj0gKG11W3RydCA9PSAiVVZCIl0gPCBtdVt0cnQgPT0gIkNPTiJdKSAmDQogICAgICAgICAgICAgICAobXVbdHJ0ID09ICJVVkIiXSA8IG11W3RydCA9PSAiU0ZOIl0pLA0KICAgICAgIGJ5ID0gR2VuZWlkXQ0KcDIgPC0gZ2dwbG90KGRtdS53Mltkbi51cCA9PSBUUlVFLCBdLA0KICAgICAgICAgICAgIGFlcyh4ID0gdHJ0LA0KICAgICAgICAgICAgICAgICB5ID0gbXUsDQogICAgICAgICAgICAgICAgIGdyb3VwID0gR2VuZWlkLA0KICAgICAgICAgICAgICAgICBmaWxsID0gdHJ0KSkgKw0KICAgICAgICBmYWNldF93cmFwKH4gR2VuZWlkLA0KICAgICAgICAgICAgICAgICAgIHNjYWxlID0gImZyZWVfeSIpICsNCiAgICAgICAgZ2VvbV9saW5lKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC41KSkgKw0KICAgICAgICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC41KSwNCiAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDIxLA0KICAgICAgICAgICAgICAgICAgIHNpemUgPSAzLA0KICAgICAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIikgKw0KICAgICAgICBzY2FsZV94X2Rpc2NyZXRlKCIiKSArDQogICAgICAgIHNjYWxlX3lfY29udGludW91cygiRGlmZmVyZW50aWFsbHkgRXhwcmVzc2VkIEdlbmVzIGF0IFdlZWsgMiIpICsNCiAgICAgICAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgiVHJlYXRtZW50IikgKw0KICAgICAgICBnZ3RpdGxlKCJHZW5lcyBEb3ducmVndWxhdGVkIGJ5IFVWQiIpDQp0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxKSkNCg0KdGlmZihmaWxlbmFtZSA9ICJ0bXAvdzJfZG5fdXAudGlmZiIsDQogICAgIGhlaWdodCA9IDYsDQogICAgIHdpZHRoID0gOCwNCiAgICAgdW5pdHMgPSAnaW4nLA0KICAgICByZXMgPSA2MDAsDQogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikNCnByaW50KHAyKQ0KZ3JhcGhpY3Mub2ZmKCkNCg0KcHJpbnQocDIpDQpgYGANCg0KIyMgRGlkIHVwLWRvd24tdXAgdHJlbmQgcGVyc2lzdD8NCmBgYHtyIGRlc2VxMl93MnNpZ25fZGVzZXFub3JtX3Bsb3RfYWxsX2RuX3VwLCBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDEyfQ0KZHAxLnRtcCA8LSBkcDFbZHAxJEdlbmVpZCAlaW4lIHVuaXF1ZShkbXUudzIkR2VuZWlkW2RtdS53MiRkbi51cF0pLCBdDQpkbXUudG1wIDwtIGRtdVtkbXUkR2VuZWlkICVpbiUgdW5pcXVlKGRtdS53MiRHZW5laWRbZG11LncyJGRuLnVwXSksIF0NCnAxIDwtIGdncGxvdChkcDEudG1wLA0KICAgICAgICAgICAgIGFlcyh4ID0gdGltZSwNCiAgICAgICAgICAgICAgICAgeSA9IGNvdW50LA0KICAgICAgICAgICAgICAgICBncm91cCA9IHRydCwNCiAgICAgICAgICAgICAgICAgZmlsbCA9IHRydCkpICsNCiAgZmFjZXRfd3JhcCh+IEdlbmVpZCwNCiAgICAgICAgICAgICBzY2FsZSA9ICJmcmVlX3kiKSArDQogIGdlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjUpLA0KICAgICAgICAgICAgIHNoYXBlID0gMjEsDQogICAgICAgICAgICAgc2l6ZSA9IDUsDQogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siKSArDQogIGdlb21fbGluZShkYXRhID0gZG11LnRtcCwNCiAgICAgICAgICAgIGFlcyh4ID0gdGltZSwNCiAgICAgICAgICAgICAgICB5ID0gbXUsDQogICAgICAgICAgICAgICAgZ3JvdXAgPSB0cnQsDQogICAgICAgICAgICAgICAgY29sb3VyID0gdHJ0KSwNCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoMC41KSwNCiAgICAgICAgICAgIGFscGhhID0gMC41LA0KICAgICAgICAgICAgc2l6ZSA9IDIpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZSgiIikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoIkRFU2VxLU5vcm1hbGl6ZWQgQ291bnRzIikgKw0KICBzY2FsZV9maWxsX2Rpc2NyZXRlKCJUcmVhdG1lbnQiKQ0KcHJpbnQocDEpDQpgYGANCg0KSW4gbWFueSBvZiB0aGVzZSBnZW5lcywgVVZCK1NGTiBtb3ZlZCBjbG9zZXIgdG8gVVZCIG92ZXIgdGltZS4NCg0KIyMgSGVhdG1hcCBmb3IgV2VlayAyIGRpZmZlcmVudGlhbGx5IG1ldGh5bGF0ZWQgZ2VuZXMNCmBgYHtyIHcyX2hlYXRtYXAsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTh9DQp1cC5kbi53MiA8LSB1bmlxdWUoYXMuY2hhcmFjdGVyKGRtdS53MiRHZW5laWRbZG11LncyJHVwLmRuXSkpDQpkbi51cC53MiA8LSB1bmlxdWUoYXMuY2hhcmFjdGVyKGRtdS53MiRHZW5laWRbZG11LncyJGRuLnVwXSkpDQpsbCA8LSB1bmlxdWUoYyh1cC5kbi53MiwNCiAgICAgICAgICAgICAgIGRuLnVwLncyKSkNCiMgMzYgZ2VuZXMNCg0KY29uX3V2Yl93ZWVrMiA8LSBkYXRhLnRhYmxlKEdlbmVpZCA9IHJlc19jb25fdXZiX3dlZWsyQHJvd25hbWVzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZzJGb2xkQ2hhbmdlID0gcmVzX2Nvbl91dmJfd2VlazJAbGlzdERhdGEkbG9nMkZvbGRDaGFuZ2UpDQoNCnNmbl91dmJfd2VlazIgPC0gZGF0YS50YWJsZShHZW5laWQgPSByZXNfc2ZuX3V2Yl93ZWVrMkByb3duYW1lcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2cyRm9sZENoYW5nZSA9IC1yZXNfc2ZuX3V2Yl93ZWVrMkBsaXN0RGF0YSRsb2cyRm9sZENoYW5nZSkNCg0KdDEgPC0gbWVyZ2UoY29uX3V2Yl93ZWVrMltjb25fdXZiX3dlZWsyJEdlbmVpZCAlaW4lIGxsLCBdLA0KICAgICAgICAgICAgc2ZuX3V2Yl93ZWVrMltzZm5fdXZiX3dlZWsyJEdlbmVpZCAlaW4lIGxsLCBdLA0KICAgICAgICAgICAgYnkgPSAiR2VuZWlkIikNCmNvbG5hbWVzKHQxKVsyOjNdIDwtIGMoIkNvbnRyb2wgdnMuIFVWQiIsDQogICAgICAgICAgICAgICAgICAgICAgICJVVkIgdnMuIFNGTitVVkIiKQ0KdDEgPC0gdDFbb3JkZXIodDEkYENvbnRyb2wgdnMuIFVWQmAsDQogICAgICAgICAgICAgICBkZWNyZWFzaW5nID0gVFJVRSksIF0NCndyaXRlLmNzdih0MSwNCiAgICAgICAgICBmaWxlID0gInRtcC93Ml9zaWduX2NoYW5nZXMuY3N2IiwNCiAgICAgICAgICByb3cubmFtZXMgPSBGQUxTRSkNCg0KbGwgPC0gbWVsdC5kYXRhLnRhYmxlKGRhdGEgPSB0MSwNCiAgICAgICAgICAgICAgICAgICAgICBpZC52YXJzID0gMSwNCiAgICAgICAgICAgICAgICAgICAgICBtZWFzdXJlLnZhcnMgPSAyOjMsDQogICAgICAgICAgICAgICAgICAgICAgdmFyaWFibGUubmFtZSA9ICJDb21wYXJpc29uIiwNCiAgICAgICAgICAgICAgICAgICAgICB2YWx1ZS5uYW1lID0gIkdlbmUgRXhwcmVzc2lvbiBEaWZmIikNCmxsJENvbXBhcmlzb24gPC0gZmFjdG9yKGxsJENvbXBhcmlzb24sDQogICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJDb250cm9sIHZzLiBVVkIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVVZCIHZzLiBTRk4rVVZCIikpDQpsdmxzIDwtIGxsW2xsJENvbXBhcmlzb24gPT0gIkNvbnRyb2wgdnMuIFVWQiIsIF0NCmxsJEdlbmVpZCA8LSBmYWN0b3IobGwkR2VuZWlkLA0KICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBsdmxzJEdlbmVpZFtvcmRlcihsdmxzJGBHZW5lIEV4cHJlc3Npb24gRGlmZmApXSkNCg0KIyBBZGQgZGVuZHJvZ3JhbS0tLS0NCmR0LmRuZHIgPC0gZGF0YS5mcmFtZSh0MVtHZW5laWQgJWluJSBsZXZlbHMobGwkR2VuZWlkKSwgXSkNCnJvd25hbWVzKGR0LmRuZHIpIDwtIGR0LmRuZHIkR2VuZQ0KZHQuZG5kciA8LSBkdC5kbmRyWywgLTFdDQoNCiMgQ29tcHV0ZSBkaXN0YW5jZXMgYmV0d2VlbiBnZW5lcy0tLS0NCnNhbXBsZURpc3RzIDwtIGRpc3QoZHQuZG5kcikNCg0KIyBNYWtlIGRlbmRyb2dyYW0gZGF0YS0tLS0NCmRoYyA8LSBhcy5kZW5kcm9ncmFtKGhjbHVzdChkID0gc2FtcGxlRGlzdHMpLA0KICAgICAgICAgICAgICAgICAgICAgaG9yaXogPSBUUlVFKQ0KZGRhdGEgPC0gZGVuZHJvX2RhdGEoZGhjLCANCiAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAicmVjdGFuZ2xlIikNCg0KIyBTZWdtZW50IGRhdGEtLS0tDQpkdHAxIDwtIHNlZ21lbnQoZGRhdGEpDQoNCiMgSGl0bWFwIGRhdGEtLS0tDQpkdHAyIDwtIGxsDQpkdHAyJEdlbmVpZCA8LSBmYWN0b3IoZHRwMiRHZW5laWQsDQogICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gZGRhdGEkbGFiZWxzJGxhYmVsKQ0KDQpvZmZzZXQuc2l6ZSA8LSA0DQoNCnAxIDwtIGdncGxvdChkYXRhID0gZHRwMikgKw0KICBjb29yZF9wb2xhcigieSIsDQogICAgICAgICAgICAgIHN0YXJ0ID0gLTAuMywNCiAgICAgICAgICAgICAgZGlyZWN0aW9uID0gLTEpICsNCiAgZ2VvbV90aWxlKGFlcyh4ID0gIGFzLm51bWVyaWMoQ29tcGFyaXNvbiksDQogICAgICAgICAgICAgICAgeSA9IEdlbmVpZCwgDQogICAgICAgICAgICAgICAgZmlsbCA9IGBHZW5lIEV4cHJlc3Npb24gRGlmZmApLA0KICAgICAgICAgICAgY29sb3IgPSAid2hpdGUiKSArDQogIGdlb21fdGV4dChkYXRhID0gZHRwMltDb21wYXJpc29uID09ICJDb250cm9sIHZzLiBVVkIiLCBdLA0KICAgICAgICAgICAgYWVzKHggPSByZXAoMS43NSwNCiAgICAgICAgICAgICAgICAgICAgICAgIG5sZXZlbHMoR2VuZWlkKSksDQogICAgICAgICAgICAgICAgeSA9IEdlbmVpZCwNCiAgICAgICAgICAgICAgICBhbmdsZSA9IDkwICsgc2VxKGZyb20gPSAzMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvID0gMzMwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoLm91dCA9IG5sZXZlbHMoR2VuZWlkKSlbYXMubnVtZXJpYyhHZW5laWQpXSArIA0KICAgICAgICAgICAgICAgICAgb2Zmc2V0LnNpemUsDQogICAgICAgICAgICAgICAgbGFiZWwgPSB1bmlxdWUoR2VuZWlkKSksDQogICAgICAgICAgICBoanVzdCA9IDApICsNCiAgZ2VvbV90ZXh0KGRhdGEgPSBkdHAyW0dlbmVpZCA9PSBsZXZlbHMoZHRwMiRHZW5laWQpWzFdLCBdLA0KICAgICAgICAgICAgYWVzKHggPSAxOm5sZXZlbHMoQ29tcGFyaXNvbiksDQogICAgICAgICAgICAgICAgeSA9IHJlcCgtb2Zmc2V0LnNpemUsDQogICAgICAgICAgICAgICAgICAgICAgICBubGV2ZWxzKENvbXBhcmlzb24pKSwNCiAgICAgICAgICAgICAgICBhbmdsZSA9IDAsDQogICAgICAgICAgICAgICAgbGFiZWwgPSBsZXZlbHMoQ29tcGFyaXNvbikpLA0KICAgICAgICAgICAgaGp1c3QgPSAxLA0KICAgICAgICAgICAgc2l6ZSA9IDUpICsNCiAgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93ID0gInJlZCIsIA0KICAgICAgICAgICAgICAgICAgICAgICBoaWdoID0gImdyZWVuIiwgDQogICAgICAgICAgICAgICAgICAgICAgIG1pZCA9ICJncmV5IiwgDQogICAgICAgICAgICAgICAgICAgICAgIG1pZHBvaW50ID0gMCwgDQogICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiIikgKw0KICBzY2FsZV95X2Rpc2NyZXRlKCIiLA0KICAgICAgICAgICAgICAgICAgIGV4cGFuZCA9IGMoMCwgMCkpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksDQogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwNCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwNCiAgICAgICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwNCiAgICAgICAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMSwgImluIiksDQogICAgICAgIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjMsICJpbiIpKSArDQogIGdlb21fc2VnbWVudChkYXRhID0gZHRwMSwNCiAgICAgICAgICAgICAgIGFlcyh4ID0gLXNxcnQoeSkgKyAwLjUsDQogICAgICAgICAgICAgICAgICAgeSA9IHgsIA0KICAgICAgICAgICAgICAgICAgIHhlbmQgPSAtc3FydCh5ZW5kKSArIDAuNSwNCiAgICAgICAgICAgICAgICAgICB5ZW5kID0geGVuZCksDQogICAgICAgICAgICAgICBzaXplID0gMSkgDQoNCnRpZmYoZmlsZW5hbWUgPSAidG1wL3NraW5fdWJ2X3cyX3Nmbl9oaXRtYXBfd2l0aF9waHlsby50aWZmIiwNCiAgICAgaGVpZ2h0ID0gOCwNCiAgICAgd2lkdGggPSA4LA0KICAgICB1bml0cyA9ICdpbicsDQogICAgIHJlcyA9IDYwMCwNCiAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQ0KcGxvdChwMSkNCmdyYXBoaWNzLm9mZigpDQoNCnByaW50KHAxKQ0KYGBgDQoNCiMjIFZlbm4gRGlhZ3JhbSwgV2VlayAyDQpgYGB7ciB3Mi12ZW5uLCBmaWcuaGVpZ2h0PTYsZmlnLndpZHRoPTR9DQojIDEuIEN0cmwgdnMuIFVWQg0KIyBhZGp1c3RlZCBwLXZhbHVlIDwgMC4xDQojIExGQyA+IDAgKHVwKSAgICAgICA6IDE1NDYsIDklDQojIExGQyA8IDAgKGRvd24pICAgICA6IDE1MzcsIDguOSUNCiMgMjMgZ2VuZXMgZG93bi11cC1kb3duDQoNCiMgMi4gU0ZOK1VWQiB2cy4gVVZCDQojIGFkanVzdGVkIHAtdmFsdWUgPCAwLjENCiMgTEZDID4gMCAodXApICAgICAgIDogMjYsIDAuMTUlDQojIExGQyA8IDAgKGRvd24pICAgICA6IDM1LCAwLjIlDQojIDEzIGdlbnMgdXAtZG93bi11cA0KDQpwMSA8LSBnZ3Bsb3QoKSArDQogIGdlb21fY2lyY2xlKGFlcyh4MCA9IGMoMSwgMiwgMSwgMiksDQogICAgICAgICAgICAgICAgICB5MCA9IGMoMSwgMSwgNCwgNCksDQogICAgICAgICAgICAgICAgICByID0gcmVwKDEsIDQpLA0KICAgICAgICAgICAgICAgICAgY29sb3IgPSBmYWN0b3IoYygyLCAxLCAxLCAyKSkpLA0KICAgICAgICAgICAgICBzaXplID0gMikgKw0KICBnZW9tX3RleHQoYWVzKHggPSByZXAoYygwLjUsIDEuNSwgMi41KSwgMiksDQogICAgICAgICAgICAgICAgeSA9IHJlcChjKDEsIDQpLCBlYWNoID0gMyksDQogICAgICAgICAgICAgICAgbGFiZWwgPSBmb3JtYXQoYygyNiwgMTMsIDM1LCAxNTQ2LCAyMywgMTUzNyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmlnLm1hcmsgPSAiLCIpKSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiZ3JlZW4iLCAicmVkIikpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQp0aWZmKGZpbGVuYW1lID0gInRtcC9za2luX3Vidl9zZm5fdzJfdmVubi50aWZmIiwNCiAgICAgaGVpZ2h0ID0gNiwNCiAgICAgd2lkdGggPSA0LA0KICAgICB1bml0cyA9ICdpbicsDQogICAgIHJlcyA9IDYwMCwNCiAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQ0KcGxvdChwMSkNCmdyYXBoaWNzLm9mZigpDQoNCnByaW50KHAxKQ0KYGBgDQoNCiMjIEVmZmVjdCBvZiBVVkIgYXQgV2VlayAxNQ0KYGBge3IgZGVzZXEyX3Jlc3VsdHNfd2VlazE1X2Nvbl91dmJ9DQpyZXNfY29uX3V2Yl93ZWVrMTUgPC0gcmVzdWx0cyhkZHMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdCA9IGMoMCwwLDAsMSwwLDEsMCwwLDApLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjEpDQpyZXNfY29uX3V2Yl93ZWVrMTUgPC0gcmVzX2Nvbl91dmJfd2VlazE1W29yZGVyKHJlc19jb25fdXZiX3dlZWsxNSRwYWRqLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWNyZWFzaW5nID0gRkFMU0UpLF0NCnN1bW1hcnkocmVzX2Nvbl91dmJfd2VlazE1KQ0KIyBvdXQgb2YgMTcyMDIgd2l0aCBub256ZXJvIHRvdGFsIHJlYWQgY291bnQNCiMgYWRqdXN0ZWQgcC12YWx1ZSA8IDAuMQ0KIyBMRkMgPiAwICh1cCkgICAgICAgOiAxNTEzLCA4LjglDQojIExGQyA8IDAgKGRvd24pICAgICA6IDE0NjMsIDguNSUNCiMgb3V0bGllcnMgWzFdICAgICAgIDogMCwgMCUNCiMgbG93IGNvdW50cyBbMl0gICAgIDogMjY2OCwgMTYlDQojIChtZWFuIGNvdW50IDwgMikNCg0KIyBIb3cgbWFueSBhZGp1c3RlZCBwLXZhbHVlcyB3ZXJlIGxlc3MgdGhhbiAwLjAxPw0Kc3VtKHJlc19jb25fdXZiX3dlZWsxNSRwYWRqIDwgMC4xLCANCiAgICBuYS5ybSA9IFRSVUUpDQojIDI5NzYNCg0KIyBOT1QgVEhFIFNBTUUgQVM/ISEhOg0KcmVzX2Nvbl91dmJfd2VlazE1LjEgPC0gcmVzdWx0cyhkZHMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyYXN0ID0gbGlzdCgidHJ0X0NPTl92c19VVkIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInRpbWUxNXcudHJ0Q09OIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4xKQ0KcmVzX2Nvbl91dmJfd2VlazE1LjEgPC0gcmVzX2Nvbl91dmJfd2VlazE1LjFbb3JkZXIocmVzX2Nvbl91dmJfd2VlazE1LjEkcGFkaiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY3JlYXNpbmcgPSBGQUxTRSksXQ0Kc3VtbWFyeShyZXNfY29uX3V2Yl93ZWVrMTUuMSkNCiMgb3V0IG9mIDE3MjAyIHdpdGggbm9uemVybyB0b3RhbCByZWFkIGNvdW50DQojIGFkanVzdGVkIHAtdmFsdWUgPCAwLjENCiMgTEZDID4gMCAodXApICAgICAgIDogNDY5LCAyLjclDQojIExGQyA8IDAgKGRvd24pICAgICA6IDQ1NSwgMi42JQ0KIyBvdXRsaWVycyBbMV0gICAgICAgOiAwLCAwJQ0KIyBsb3cgY291bnRzIFsyXSAgICAgOiA0MDAyLCAyMyUNCiMgKG1lYW4gY291bnQgPCA2KQ0KDQojIEhvdyBtYW55IGFkanVzdGVkIHAtdmFsdWVzIHdlcmUgbGVzcyB0aGFuIDAuMDE/DQpzdW0ocmVzX2Nvbl91dmJfd2VlazE1LjEkcGFkaiA8IDAuMSwgDQogICAgbmEucm0gPSBUUlVFKQ0KIyA5MjQNCg0KIyBNQSBwbG90DQojIFNhdmUgZm9yIHB1YmxpY2F0aW9uDQp0aWZmKGZpbGVuYW1lID0gInRtcC9tYV93MTVfY29uX3V2Yi50aWZmIiwNCiAgICAgaGVpZ2h0ID0gNiwNCiAgICAgd2lkdGggPSA3LA0KICAgICB1bml0cyA9ICdpbicsDQogICAgIHJlcyA9IDYwMCwNCiAgICAgY29tcHJlc3Npb24gPSAibHp3K3AiKQ0KcGxvdE1BKHJlc19jb25fdXZiX3dlZWsxNSwNCiAgICAgICBtYWluID0gIkNvbnRyb2wgdnMuIFVWQiBhdCBXZWVrIDE1IiwNCiAgICAgICBhbHBoYSA9IDAuOCkNCmdyYXBoaWNzLm9mZigpDQoNCnBsb3RNQShyZXNfY29uX3V2Yl93ZWVrMTUsDQogICAgICAgbWFpbiA9ICJDb250cm9sIHZzLiBVVkIgYXQgV2VlayAxNSIsDQogICAgICAgYWxwaGEgPSAwLjgpDQpgYGANCg0KIyMgUHJvdGVjdGl2ZSBlZmZlY3Qgb2YgU0ZOIGF0IFdlZWsgMTUNCmBgYHtyIGRlc2VxMl9yZXN1bHRzX3dlZWsxNV9zZm5fdXZifQ0KcmVzX3Nmbl91dmJfd2VlazE1IDwtIHJlc3VsdHMoZGRzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJhc3QgPSBjKDAsMCwwLDAsMSwwLDAsMSwwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4xKQ0KcmVzX3Nmbl91dmJfd2VlazE1IDwtIHJlc19zZm5fdXZiX3dlZWsxNVtvcmRlcihyZXNfc2ZuX3V2Yl93ZWVrMTUkcGFkaiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjcmVhc2luZyA9IEZBTFNFKSxdDQpzdW1tYXJ5KHJlc19zZm5fdXZiX3dlZWsxNSkNCiMgb3V0IG9mIDE3MjAyIHdpdGggbm9uemVybyB0b3RhbCByZWFkIGNvdW50DQojIGFkanVzdGVkIHAtdmFsdWUgPCAwLjENCiMgTEZDID4gMCAodXApICAgICAgIDogMjAsIDAuMTIlDQojIExGQyA8IDAgKGRvd24pICAgICA6IDEwLCAwLjA1OCUNCiMgb3V0bGllcnMgWzFdICAgICAgIDogMCwgMCUNCiMgbG93IGNvdW50cyBbMl0gICAgIDogNzAwNCwgNDElDQojIChtZWFuIGNvdW50IDwgNTMpDQoNCiMgSG93IG1hbnkgYWRqdXN0ZWQgcC12YWx1ZXMgd2VyZSBsZXNzIHRoYW4gMC4wNT8NCnN1bShyZXNfc2ZuX3V2Yl93ZWVrMTUkcGFkaiA8IDAuMSwgDQogICAgbmEucm0gPSBUUlVFKQ0KIyAzMA0KDQojIE5PVCBUSEUgU0FNRSBBUyEhIToNCnJlc19zZm5fdXZiX3dlZWsxNS4xIDwtIHJlc3VsdHMoZGRzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cmFzdCA9IGxpc3QoInRydF9TRk5fdnNfVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0aW1lMTV3LnRydFNGTiIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMSkNCnJlc19zZm5fdXZiX3dlZWsxNS4xIDwtIHJlc19zZm5fdXZiX3dlZWsxNS4xW29yZGVyKHJlc19zZm5fdXZiX3dlZWsxNS4xJHBhZGosDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWNyZWFzaW5nID0gRkFMU0UpLF0NCnN1bW1hcnkocmVzX3Nmbl91dmJfd2VlazE1LjEpDQojIG91dCBvZiAxNzIwMiB3aXRoIG5vbnplcm8gdG90YWwgcmVhZCBjb3VudA0KIyBhZGp1c3RlZCBwLXZhbHVlIDwgMC4xDQojIExGQyA+IDAgKHVwKSAgICAgICA6IDE0LCAwLjA4MSUNCiMgTEZDIDwgMCAoZG93bikgICAgIDogMjQsIDAuMTQlDQojIG91dGxpZXJzIFsxXSAgICAgICA6IDAsIDAlDQojIGxvdyBjb3VudHMgWzJdICAgICA6IDMzMzUsIDE5JQ0KIyAobWVhbiBjb3VudCA8IDQpDQoNCiMgSG93IG1hbnkgYWRqdXN0ZWQgcC12YWx1ZXMgd2VyZSBsZXNzIHRoYW4gMC4xPw0Kc3VtKHJlc19zZm5fdXZiX3dlZWsxNS4xJHBhZGogPCAwLjEsIA0KICAgIG5hLnJtID0gVFJVRSkNCiMgMzgNCg0KIyBNQSBwbG90DQojIFNhdmUgZm9yIHB1YmxpY2F0aW9uDQp0aWZmKGZpbGVuYW1lID0gInRtcC9tYV93Ml9zZm5fdXZiLnRpZmYiLA0KICAgICBoZWlnaHQgPSA2LA0KICAgICB3aWR0aCA9IDcsDQogICAgIHVuaXRzID0gJ2luJywNCiAgICAgcmVzID0gNjAwLA0KICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpDQpwcmludChwbG90TUEocmVzX3Nmbl91dmJfd2VlazE1LA0KICAgICAgICAgICAgIG1haW4gPSAiVVZCK1NGTiB2cyBVVkIgYXQgV2VlayAxNSIsDQogICAgICAgICAgICAgYWxwaGEgPSAwLjgpKQ0KZ3JhcGhpY3Mub2ZmKCkNCg0KcHJpbnQocGxvdE1BKHJlc19zZm5fdXZiX3dlZWsxNSwNCiAgICAgICAgICAgICBtYWluID0gIlVWQitTRk4gdnMgVVZCIGF0IFdlZWsgMTUiLA0KICAgICAgICAgICAgIGFscGhhID0gMC44KSkNCg0KYGBgDQoNCiMjIEdlbmVzIHRoYXQgd2VyZSBzaWduaWZpY2FudGx5IGRpZmZlcmVudGlhdGVkIGF0IGJvdGggY29tcGFyaXNvbnMgYXQgV2VlayAxNQ0KYGBge3Igc2lnbl93MTV9DQpsZ2VuZS53MTUuY29uIDwtIHVuaXF1ZShyZXNfY29uX3V2Yl93ZWVrMTVAcm93bmFtZXNbcmVzX2Nvbl91dmJfd2VlazE1JHBhZGogPCAwLjFdKQ0KbGdlbmUudzE1LnNmbiA8LSB1bmlxdWUocmVzX3Nmbl91dmJfd2VlazE1QHJvd25hbWVzW3Jlc19zZm5fdXZiX3dlZWsxNSRwYWRqIDwgMC4xXSkNCmxnZW5lLncxNSA8LSBsZ2VuZS53MTUuY29uW2xnZW5lLncxNS5jb24gJWluJSBsZ2VuZS53MTUuc2ZuXQ0KbGdlbmUudzE1IDwtIGxnZW5lLncxNSBbIWlzLm5hKGxnZW5lLncxNSApXQ0KbGVuZ3RoKHVuaXF1ZShsZ2VuZS53MTUpKQ0KYGBgDQpQbG90IG9mIERFU2VxLW5vcm1hbGl6ZWRjb3VudHMgb2YgZ2VuZXMgc2lnbmlmaWNhbnQgaW4gYm90aCBjb21wYXJpc29ucyBhdCBXZWVrIDE1OiAgIA0KDQpgYGB7ciBkZXNlcTJfdzE1c2lnbl9kZXNlcW5vcm19DQojIEdldCB0aGUgREVTZXEtbm9ybWFsaXplIGNvdW50cw0KZHAxIDwtIGxpc3QoKQ0KZm9yIChpIGluIDE6bGVuZ3RoKGxnZW5lLncxNSkpIHsNCiAgb3V0IDwtIHBsb3RDb3VudHMoZGRzLCANCiAgICAgICAgICAgICAgICAgICAgZ2VuZSA9IGxnZW5lLncxNVtbaV1dLA0KICAgICAgICAgICAgICAgICAgICBpbnRncm91cCA9IGMoInRydCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidGltZSIpLA0KICAgICAgICAgICAgICAgICAgICByZXR1cm5EYXRhID0gVFJVRSkNCiAgZHAxW1tpXV0gPC0gZGF0YS50YWJsZShHZW5laWQgPSBsZ2VuZS53MTVbW2ldXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBTYW1wbGUgPSByb3duYW1lcyhvdXQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG91dCkNCn0NCmRwMSA8LSByYmluZGxpc3QoZHAxKQ0KZHAxJHRydCA8LSBmYWN0b3IoZHAxJHRydCwNCiAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkNPTiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJVVkIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU0ZOIikpDQpkcDEkdGltZSA8LSBmYWN0b3IoZHAxJHRpbWUsDQogICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiMDJ3IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIxNXciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjI1dyIpLA0KICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIldlZWsgMiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV2VlayAxNSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiV2VlayAyNSIpKQ0KZHAxJEdlbmVpZCA8LSBmYWN0b3IoZHAxJEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGxnZW5lLncxNSkNCmRwMVssIG11IDo9IG1lYW4oY291bnQsDQogICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSksDQogICAgYnkgPSBjKCJHZW5laWQiLA0KICAgICAgICAgICAidHJ0IiwNCiAgICAgICAgICAgInRpbWUiKV0NCmRtdSA8LSB1bmlxdWUoZHAxWywgLWMoIlNhbXBsZSIsDQogICAgICAgICAgICAgICAgICAgICAgICJjb3VudCIpXSkNCmRhdGF0YWJsZShoZWFkKGRtdSksDQogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSwNCiAgICAgICAgICBjbGFzcyA9ICJjZWxsLWJvcmRlciBzdHJpcGUiKSAlPiUgDQogIGZvcm1hdFJvdW5kKGNvbHVtbnMgPSA0LA0KICAgICAgICAgICAgICBkaWdpdHMgPSAyKQ0KYGBgDQoNCmBgYHtyIGRlc2VxMl93MTVzaWduX2Rlc2Vxbm9ybV93MTVfdXBfZG4sIGVjaG8gPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gOH0NCmRtdS53MTUgPC0gZG11W3RpbWUgPT0gIldlZWsgMTUiLCBdDQpkbXUudzE1WywgdXAuZG4gOj0gKG11W3RydCA9PSAiVVZCIl0gPiBtdVt0cnQgPT0gIkNPTiJdKSAmDQogICAgICAgICAgICAgICAobXVbdHJ0ID09ICJVVkIiXSA+IG11W3RydCA9PSAiU0ZOIl0pLA0KICAgICAgIGJ5ID0gR2VuZWlkXQ0KcDEgPC0gZ2dwbG90KGRtdS53MTVbdXAuZG4gPT0gVFJVRSwgXSwNCiAgICAgICAgICAgICBhZXMoeCA9IHRydCwNCiAgICAgICAgICAgICAgICAgeSA9IG11LA0KICAgICAgICAgICAgICAgICBncm91cCA9IEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgZmlsbCA9IHRydCkpICsNCiAgICAgICAgZmFjZXRfd3JhcCh+IEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgICBzY2FsZSA9ICJmcmVlX3kiKSArDQogICAgICAgIGdlb21fbGluZShwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSkpICsNCiAgICAgICAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICAgICAgICBzaXplID0gMywNCiAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgICAgICAgc2NhbGVfeF9kaXNjcmV0ZSgiIikgKw0KICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoIkRpZmZlcmVudGlhbGx5IEV4cHJlc3NlZCBHZW5lcyBhdCBXZWVrIDE1IikgKw0KICAgICAgICBzY2FsZV9maWxsX2Rpc2NyZXRlKCJUcmVhdG1lbnQiKSArDQogICAgICAgIGdndGl0bGUoIkdlbmVzIFVwcmVndWxhdGVkIGJ5IFVWQiIpDQp0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxKSkNCg0KdGlmZihmaWxlbmFtZSA9ICJ0bXAvdzE1X3VwX2RuLnRpZmYiLA0KICAgICBoZWlnaHQgPSA2LA0KICAgICB3aWR0aCA9IDgsDQogICAgIHVuaXRzID0gJ2luJywNCiAgICAgcmVzID0gMzAwLA0KICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpDQpwcmludChwMSkNCmdyYXBoaWNzLm9mZigpDQoNCnByaW50KHAxKQ0KYGBgDQoNCiMjIERpZCBkb3duLXVwLWRvd24gdHJlbmQgcGVyc2lzdD8NCmBgYHtyIGRlc2VxMl93MTVzaWduX2Rlc2Vxbm9ybV9wbG90X2FsbF91cF9kbiwgZmlnLmhlaWdodCA9IDEwLCBmaWcud2lkdGggPSAxMn0NCmRwMS50bXAgPC0gZHAxW2RwMSRHZW5laWQgJWluJSB1bmlxdWUoZG11LncxNSRHZW5laWRbZG11LncxNSR1cC5kbl0pLCBdDQpkbXUudG1wIDwtIGRtdVtkbXUkR2VuZWlkICVpbiUgdW5pcXVlKGRtdS53MTUkR2VuZWlkW2RtdS53MTUkdXAuZG5dKSwgXQ0KcDEgPC0gZ2dwbG90KGRwMS50bXAsDQogICAgICAgICAgICAgYWVzKHggPSB0aW1lLA0KICAgICAgICAgICAgICAgICB5ID0gY291bnQsDQogICAgICAgICAgICAgICAgIGdyb3VwID0gdHJ0LA0KICAgICAgICAgICAgICAgICBmaWxsID0gdHJ0KSkgKw0KICBmYWNldF93cmFwKH4gR2VuZWlkLA0KICAgICAgICAgICAgIHNjYWxlID0gImZyZWVfeSIpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICBzaXplID0gNSwNCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBkbXUudG1wLA0KICAgICAgICAgICAgYWVzKHggPSB0aW1lLA0KICAgICAgICAgICAgICAgIHkgPSBtdSwNCiAgICAgICAgICAgICAgICBncm91cCA9IHRydCwNCiAgICAgICAgICAgICAgICBjb2xvdXIgPSB0cnQpLA0KICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjUpLA0KICAgICAgICAgICAgYWxwaGEgPSAwLjUsDQogICAgICAgICAgICBzaXplID0gMikgKw0KICBzY2FsZV94X2Rpc2NyZXRlKCIiKSArDQogIHNjYWxlX3lfY29udGludW91cygiREVTZXEtTm9ybWFsaXplZCBDb3VudHMiKSArDQogIHNjYWxlX2ZpbGxfZGlzY3JldGUoIlRyZWF0bWVudCIpDQpwcmludChwMSkNCmBgYA0KDQpgYGB7ciBkZXNlcTJfdzE1c2lnbl9kZXNlcW5vcm1fdzE1X2RuX3VwLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDh9DQpkbXUudzE1WywgZG4udXAgOj0gKG11W3RydCA9PSAiVVZCIl0gPCBtdVt0cnQgPT0gIkNPTiJdKSAmDQogICAgICAgICAgICAgICAobXVbdHJ0ID09ICJVVkIiXSA8IG11W3RydCA9PSAiU0ZOIl0pLA0KICAgICAgIGJ5ID0gR2VuZWlkXQ0KcDIgPC0gZ2dwbG90KGRtdS53MTVbZG4udXAgPT0gVFJVRSwgXSwNCiAgICAgICAgICAgICBhZXMoeCA9IHRydCwNCiAgICAgICAgICAgICAgICAgeSA9IG11LA0KICAgICAgICAgICAgICAgICBncm91cCA9IEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgZmlsbCA9IHRydCkpICsNCiAgICAgICAgZmFjZXRfd3JhcCh+IEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgICBzY2FsZSA9ICJmcmVlX3kiKSArDQogICAgICAgIGdlb21fbGluZShwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSkpICsNCiAgICAgICAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICAgICAgICBzaXplID0gMywNCiAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgICAgICAgc2NhbGVfeF9kaXNjcmV0ZSgiIikgKw0KICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMoIkRpZmZlcmVudGlhbGx5IEV4cHJlc3NlZCBHZW5lcyBhdCBXZWVrIDE1IikgKw0KICAgICAgICBzY2FsZV9maWxsX2Rpc2NyZXRlKCJUcmVhdG1lbnQiKSArDQogICAgICAgIGdndGl0bGUoIkdlbmVzIERvd25yZWd1bGF0ZWQgYnkgVVZCIikNCnRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDEpKQ0KDQp0aWZmKGZpbGVuYW1lID0gInRtcC93MTVfZG5fdXAudGlmZiIsDQogICAgIGhlaWdodCA9IDYsDQogICAgIHdpZHRoID0gOCwNCiAgICAgdW5pdHMgPSAnaW4nLA0KICAgICByZXMgPSA2MDAsDQogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikNCnByaW50KHAyKQ0KZ3JhcGhpY3Mub2ZmKCkNCg0KcHJpbnQocDIpDQpgYGANCg0KIyMgRGlkIHVwLWRvd24tdXAgdHJlbmQgcGVyc2lzdD8NCmBgYHtyIGRlc2VxMl93MTVzaWduX2Rlc2Vxbm9ybV9wbG90X2FsbF9kbl91cCwgZmlnLmhlaWdodCA9IDEwLCBmaWcud2lkdGggPSAxMn0NCmRwMS50bXAgPC0gZHAxW2RwMSRHZW5laWQgJWluJSB1bmlxdWUoZG11LncxNSRHZW5laWRbZG11LncxNSRkbi51cF0pLCBdDQpkbXUudG1wIDwtIGRtdVtkbXUkR2VuZWlkICVpbiUgdW5pcXVlKGRtdS53MTUkR2VuZWlkW2RtdS53MTUkZG4udXBdKSwgXQ0KcDEgPC0gZ2dwbG90KGRwMS50bXAsDQogICAgICAgICAgICAgYWVzKHggPSB0aW1lLA0KICAgICAgICAgICAgICAgICB5ID0gY291bnQsDQogICAgICAgICAgICAgICAgIGdyb3VwID0gdHJ0LA0KICAgICAgICAgICAgICAgICBmaWxsID0gdHJ0KSkgKw0KICBmYWNldF93cmFwKH4gR2VuZWlkLA0KICAgICAgICAgICAgIHNjYWxlID0gImZyZWVfeSIpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICBzaXplID0gNSwNCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBkbXUudG1wLA0KICAgICAgICAgICAgYWVzKHggPSB0aW1lLA0KICAgICAgICAgICAgICAgIHkgPSBtdSwNCiAgICAgICAgICAgICAgICBncm91cCA9IHRydCwNCiAgICAgICAgICAgICAgICBjb2xvdXIgPSB0cnQpLA0KICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjUpLA0KICAgICAgICAgICAgYWxwaGEgPSAwLjUsDQogICAgICAgICAgICBzaXplID0gMikgKw0KICBzY2FsZV94X2Rpc2NyZXRlKCIiKSArDQogIHNjYWxlX3lfY29udGludW91cygiREVTZXEtTm9ybWFsaXplZCBDb3VudHMiKSArDQogIHNjYWxlX2ZpbGxfZGlzY3JldGUoIlRyZWF0bWVudCIpDQpwcmludChwMSkNCmBgYA0KDQojIyBIZWF0bWFwIGZvciBXZWVrIDE1IGRpZmZlcmVudGlhbGx5IG1ldGh5bGF0ZWQgZ2VuZXMNCmBgYHtyIHcxNV9oZWF0bWFwLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQ0KdXAuZG4udzE1IDwtIHVuaXF1ZShhcy5jaGFyYWN0ZXIoZG11LncxNSRHZW5laWRbZG11LncxNSR1cC5kbl0pKQ0KZG4udXAudzE1IDwtIHVuaXF1ZShhcy5jaGFyYWN0ZXIoZG11LncxNSRHZW5laWRbZG11LncxNSRkbi51cF0pKQ0KbGwgPC0gdW5pcXVlKGModXAuZG4udzE1LA0KICAgICAgICAgICAgICAgZG4udXAudzE1KSkNCiMgMTYgZ2VuZXMNCg0KY29uX3V2Yl93ZWVrMTUgPC0gZGF0YS50YWJsZShHZW5laWQgPSByZXNfY29uX3V2Yl93ZWVrMTVAcm93bmFtZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZzJGb2xkQ2hhbmdlID0gcmVzX2Nvbl91dmJfd2VlazE1QGxpc3REYXRhJGxvZzJGb2xkQ2hhbmdlKQ0KDQpzZm5fdXZiX3dlZWsxNSA8LSBkYXRhLnRhYmxlKEdlbmVpZCA9IHJlc19zZm5fdXZiX3dlZWsxNUByb3duYW1lcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nMkZvbGRDaGFuZ2UgPSAtcmVzX3Nmbl91dmJfd2VlazE1QGxpc3REYXRhJGxvZzJGb2xkQ2hhbmdlKQ0KDQp0MSA8LSBtZXJnZShjb25fdXZiX3dlZWsxNVtjb25fdXZiX3dlZWsxNSRHZW5laWQgJWluJSBsbCwgXSwNCiAgICAgICAgICAgIHNmbl91dmJfd2VlazE1W3Nmbl91dmJfd2VlazE1JEdlbmVpZCAlaW4lIGxsLCBdLA0KICAgICAgICAgICAgYnkgPSAiR2VuZWlkIikNCmNvbG5hbWVzKHQxKVsyOjNdIDwtIGMoIkNvbnRyb2wgdnMuIFVWQiIsDQogICAgICAgICAgICAgICAgICAgICAgICJVVkIgdnMuIFNGTitVVkIiKQ0KdDEgPC0gdDFbb3JkZXIodDEkYENvbnRyb2wgdnMuIFVWQmAsDQogICAgICAgICAgICAgICBkZWNyZWFzaW5nID0gVFJVRSksIF0NCndyaXRlLmNzdih0MSwNCiAgICAgICAgICBmaWxlID0gInRtcC93MTVfc2lnbl9jaGFuZ2VzLmNzdiIsDQogICAgICAgICAgcm93Lm5hbWVzID0gRkFMU0UpDQoNCmxsIDwtIG1lbHQuZGF0YS50YWJsZShkYXRhID0gdDEsDQogICAgICAgICAgICAgICAgICAgICAgaWQudmFycyA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZS52YXJzID0gMjozLA0KICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlLm5hbWUgPSAiQ29tcGFyaXNvbiIsDQogICAgICAgICAgICAgICAgICAgICAgdmFsdWUubmFtZSA9ICJHZW5lIEV4cHJlc3Npb24gRGlmZiIpDQpsbCRDb21wYXJpc29uIDwtIGZhY3RvcihsbCRDb21wYXJpc29uLA0KICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiQ29udHJvbCB2cy4gVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlVWQiB2cy4gU0ZOK1VWQiIpKQ0KbHZscyA8LSBsbFtsbCRDb21wYXJpc29uID09ICJDb250cm9sIHZzLiBVVkIiLCBdDQpsbCRHZW5laWQgPC0gZmFjdG9yKGxsJEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gbHZscyRHZW5laWRbb3JkZXIobHZscyRgR2VuZSBFeHByZXNzaW9uIERpZmZgKV0pDQoNCiMgQWRkIGRlbmRyb2dyYW0tLS0tDQpkdC5kbmRyIDwtIGRhdGEuZnJhbWUodDFbR2VuZWlkICVpbiUgbGV2ZWxzKGxsJEdlbmVpZCksIF0pDQpyb3duYW1lcyhkdC5kbmRyKSA8LSBkdC5kbmRyJEdlbmUNCmR0LmRuZHIgPC0gZHQuZG5kclssIC0xXQ0KDQojIENvbXB1dGUgZGlzdGFuY2VzIGJldHdlZW4gZ2VuZXMtLS0tDQpzYW1wbGVEaXN0cyA8LSBkaXN0KGR0LmRuZHIpDQoNCiMgTWFrZSBkZW5kcm9ncmFtIGRhdGEtLS0tDQpkaGMgPC0gYXMuZGVuZHJvZ3JhbShoY2x1c3QoZCA9IHNhbXBsZURpc3RzKSwNCiAgICAgICAgICAgICAgICAgICAgIGhvcml6ID0gVFJVRSkNCmRkYXRhIDwtIGRlbmRyb19kYXRhKGRoYywgDQogICAgICAgICAgICAgICAgICAgICB0eXBlID0gInJlY3RhbmdsZSIpDQoNCiMgU2VnbWVudCBkYXRhLS0tLQ0KZHRwMSA8LSBzZWdtZW50KGRkYXRhKQ0KDQojIEhpdG1hcCBkYXRhLS0tLQ0KZHRwMiA8LSBsbA0KZHRwMiRHZW5laWQgPC0gZmFjdG9yKGR0cDIkR2VuZWlkLA0KICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGRkYXRhJGxhYmVscyRsYWJlbCkNCg0Kb2Zmc2V0LnNpemUgPC0gNA0KDQpwMSA8LSBnZ3Bsb3QoZGF0YSA9IGR0cDIpICsNCiAgY29vcmRfcG9sYXIoInkiLA0KICAgICAgICAgICAgICBzdGFydCA9IC0wLjMsDQogICAgICAgICAgICAgIGRpcmVjdGlvbiA9IC0xKSArDQogIGdlb21fdGlsZShhZXMoeCA9ICBhcy5udW1lcmljKENvbXBhcmlzb24pLA0KICAgICAgICAgICAgICAgIHkgPSBHZW5laWQsIA0KICAgICAgICAgICAgICAgIGZpbGwgPSBgR2VuZSBFeHByZXNzaW9uIERpZmZgKSwNCiAgICAgICAgICAgIGNvbG9yID0gIndoaXRlIikgKw0KICBnZW9tX3RleHQoZGF0YSA9IGR0cDJbQ29tcGFyaXNvbiA9PSAiQ29udHJvbCB2cy4gVVZCIiwgXSwNCiAgICAgICAgICAgIGFlcyh4ID0gcmVwKDEuNzUsDQogICAgICAgICAgICAgICAgICAgICAgICBubGV2ZWxzKEdlbmVpZCkpLA0KICAgICAgICAgICAgICAgIHkgPSBHZW5laWQsDQogICAgICAgICAgICAgICAgYW5nbGUgPSA5MCArIHNlcShmcm9tID0gOTAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0byA9IDMzMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aC5vdXQgPSBubGV2ZWxzKEdlbmVpZCkpW2FzLm51bWVyaWMoR2VuZWlkKV0gKyANCiAgICAgICAgICAgICAgICAgIG9mZnNldC5zaXplLA0KICAgICAgICAgICAgICAgIGxhYmVsID0gdW5pcXVlKEdlbmVpZCkpLA0KICAgICAgICAgICAgaGp1c3QgPSAwKSArDQogIGdlb21fdGV4dChkYXRhID0gZHRwMltHZW5laWQgPT0gbGV2ZWxzKGR0cDIkR2VuZWlkKVsxXSwgXSwNCiAgICAgICAgICAgIGFlcyh4ID0gMTpubGV2ZWxzKENvbXBhcmlzb24pLA0KICAgICAgICAgICAgICAgIHkgPSByZXAoLW9mZnNldC5zaXplLA0KICAgICAgICAgICAgICAgICAgICAgICAgbmxldmVscyhDb21wYXJpc29uKSksDQogICAgICAgICAgICAgICAgYW5nbGUgPSAwLA0KICAgICAgICAgICAgICAgIGxhYmVsID0gbGV2ZWxzKENvbXBhcmlzb24pKSwNCiAgICAgICAgICAgIGhqdXN0ID0gMSwNCiAgICAgICAgICAgIHNpemUgPSA1KSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJyZWQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgaGlnaCA9ICJncmVlbiIsIA0KICAgICAgICAgICAgICAgICAgICAgICBtaWQgPSAiZ3JleSIsIA0KICAgICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IDAsIA0KICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIiIpICsNCiAgc2NhbGVfeV9kaXNjcmV0ZSgiIiwNCiAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBjKDAsIDApKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLA0KICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsDQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksDQogICAgICAgIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsDQogICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDEsICJpbiIpLA0KICAgICAgICBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMC4zLCAiaW4iKSkgKw0KICBnZW9tX3NlZ21lbnQoZGF0YSA9IGR0cDEsDQogICAgICAgICAgICAgICBhZXMoeCA9IC1zcXJ0KHkpICsgMC41LA0KICAgICAgICAgICAgICAgICAgIHkgPSB4LCANCiAgICAgICAgICAgICAgICAgICB4ZW5kID0gLXNxcnQoeWVuZCkgKyAwLjUsDQogICAgICAgICAgICAgICAgICAgeWVuZCA9IHhlbmQpLA0KICAgICAgICAgICAgICAgc2l6ZSA9IDEpIA0KDQp0aWZmKGZpbGVuYW1lID0gInRtcC9za2luX3Vidl93MTVfc2ZuX2hpdG1hcF93aXRoX3BoeWxvLnRpZmYiLA0KICAgICBoZWlnaHQgPSA4LA0KICAgICB3aWR0aCA9IDgsDQogICAgIHVuaXRzID0gJ2luJywNCiAgICAgcmVzID0gNjAwLA0KICAgICBjb21wcmVzc2lvbiA9ICJsencrcCIpDQpwbG90KHAxKQ0KZ3JhcGhpY3Mub2ZmKCkNCg0KcHJpbnQocDEpDQpgYGANCg0KDQojIyBWZW5uIERpYWdyYW0sIFdlZWsgMTUNCmBgYHtyIHcxNS12ZW5uLCBmaWcuaGVpZ2h0PTYsZmlnLndpZHRoPTR9DQojIG91dCBvZiAxNzIwMiB3aXRoIG5vbnplcm8gdG90YWwgcmVhZCBjb3VudA0KIyAxLiBDdHJsIHZzLiBVVkINCiMgYWRqdXN0ZWQgcC12YWx1ZSA8IDAuMQ0KIyBMRkMgPiAwICh1cCkgICAgICAgOiAxNTEzLCA4LjglDQojIExGQyA8IDAgKGRvd24pICAgICA6IDE0NjMsIDguNSUNCiMgMiBnZW5lcyBkb3duLXVwLWRvd24NCg0KIyAyLiBTRk4rVVZCIHZzLiBVVkINCiMgYWRqdXN0ZWQgcC12YWx1ZSA8IDAuMQ0KIyBMRkMgPiAwICh1cCkgICAgICAgOiAyMCwgMC4xMiUNCiMgTEZDIDwgMCAoZG93bikgICAgIDogMTAsIDAuMDU4JQ0KIyA5IGdlbnMgdXAtZG93bi11cA0KDQpwMSA8LSBnZ3Bsb3QoKSArDQogIGdlb21fY2lyY2xlKGFlcyh4MCA9IGMoMSwgMiwgMSwgMiksDQogICAgICAgICAgICAgICAgICB5MCA9IGMoMSwgMSwgNCwgNCksDQogICAgICAgICAgICAgICAgICByID0gcmVwKDEsIDQpLA0KICAgICAgICAgICAgICAgICAgY29sb3IgPSBmYWN0b3IoYygyLCAxLCAxLCAyKSkpLA0KICAgICAgICAgICAgICBzaXplID0gMikgKw0KICBnZW9tX3RleHQoYWVzKHggPSByZXAoYygwLjUsIDEuNSwgMi41KSwgMiksDQogICAgICAgICAgICAgICAgeSA9IHJlcChjKDEsIDQpLCBlYWNoID0gMyksDQogICAgICAgICAgICAgICAgbGFiZWwgPSBmb3JtYXQoYygyMCwgOSwgMTAsIDE1MTMsIDIsIDE0NjMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpZy5tYXJrID0gIiwiKSkpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImdyZWVuIiwgInJlZCIpKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KdGlmZihmaWxlbmFtZSA9ICJ0bXAvc2tpbl91YnZfc2ZuX3cyX3Zlbm4udGlmZiIsDQogICAgIGhlaWdodCA9IDYsDQogICAgIHdpZHRoID0gNCwNCiAgICAgdW5pdHMgPSAnaW4nLA0KICAgICByZXMgPSA2MDAsDQogICAgIGNvbXByZXNzaW9uID0gImx6dytwIikNCnBsb3QocDEpDQpncmFwaGljcy5vZmYoKQ0KDQpwcmludChwMSkNCmBgYA0KDQojIyBJbnRlcmFjdGlvbnMgdGVybXMNClRlc3RzIGlmIHRoZSBlZmZlY3Qgb2YgTk9UIHRyZWF0aW5nIHdpdGggVVZCIHZzLiB0cmVhdGluZyB3aXRoIFVWQiBpcyBkaWZmZXJlbnQgYXQgV2VlayAxNSBjb21wYXJlZCB0byBXZWVrIDI6ICAgIA0KYGBge3IgZGVzZXEyX3dlZWsyX3dlZWsxNV9yZXN1bHRzX2ludF9jb25fdXZifQ0KcmVzX2ludF9jb25fdXZiX3dlZWsgPC0gcmVzdWx0cyhkZHMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gInRpbWUxNXcudHJ0Q09OIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjEpDQpyZXNfaW50X2Nvbl91dmJfd2VlayA8LSByZXNfaW50X2Nvbl91dmJfd2Vla1tvcmRlcihyZXNfaW50X2Nvbl91dmJfd2VlayRwYWRqLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjcmVhc2luZyA9IEZBTFNFKSxdDQpwcmludChyZXNfaW50X2Nvbl91dmJfd2VlaykNCnN1bW1hcnkocmVzX2ludF9jb25fdXZiX3dlZWspDQoNCiMgSG93IG1hbnkgYWRqdXN0ZWQgcC12YWx1ZXMgd2VyZSBsZXNzIHRoYW4gMC4wNT8NCnN1bShyZXNfaW50X2Nvbl91dmJfd2VlayRwYWRqIDwgMC4xLCANCiAgICBuYS5ybSA9IFRSVUUpDQoNCiMgTUEgcGxvdA0KcHJpbnQocGxvdE1BKHJlc19pbnRfY29uX3V2Yl93ZWVrLA0KICAgICAgICAgICAgIG1haW4gPSAiKENvbnRyb2wgdnMuIFVWQikgeCBUSW1lIEludGVyYWN0aW9uIiwNCiAgICAgICAgICAgICBhbHBoYSA9IDAuOSkpDQoNCmBgYA0KDQpUZXN0cyBpZiB0aGUgZWZmZWN0IG9mIHRyZWF0aW5nIHdpdGggVVZCK1NGTiB2cy4gdHJlYXRpbmcgd2l0aCBVVkIgaXMgZGlmZmVyZW50IGF0IFdlZWsgMTUgY29tcGFyZWQgdG8gV2VlayAyOiAgICANCmBgYHtyIGRlc2VxMl93ZWVrMl93ZWVrMTVfcmVzdWx0c19pbnRfc2ZuX3V2Yn0NCnJlc19pbnRfc2ZuX3V2Yl93ZWVrIDwtIHJlc3VsdHMoZGRzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJ0aW1lMTV3LnRydFNGTiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4xKQ0KcmVzX2ludF9zZm5fdXZiX3dlZWsgPC0gcmVzX2ludF9zZm5fdXZiX3dlZWtbb3JkZXIocmVzX2ludF9zZm5fdXZiX3dlZWskcGFkaiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY3JlYXNpbmcgPSBGQUxTRSksXQ0KcHJpbnQocmVzX2ludF9zZm5fdXZiX3dlZWspDQpzdW1tYXJ5KHJlc19pbnRfc2ZuX3V2Yl93ZWVrKQ0KDQojIEhvdyBtYW55IGFkanVzdGVkIHAtdmFsdWVzIHdlcmUgbGVzcyB0aGFuIDAuMDU/DQpzdW0ocmVzX2ludF9zZm5fdXZiX3dlZWskcGFkaiA8IDAuMSwgDQogICAgbmEucm0gPSBUUlVFKQ0KDQojIE1BIHBsb3QNCnByaW50KHBsb3RNQShyZXNfaW50X3Nmbl91dmJfd2VlaykpDQoNCiMgTk9URTogc2FtZSBhcyANCiMgcmVzIDwtIHJlc3VsdHMoZGRzLCANCiMgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjA1KQ0KIyByZXMgPC0gcmVzW29yZGVyKHJlcyRwYWRqLCBkZWNyZWFzaW5nID0gRkFMU0UpLF0NCiMgcmVzDQpgYGANCg0KKipOT1RFKio6IEJ5IGRlZmF1bHQsIHRoZSAqKnJlc3VsdHMoZGRzKSoqKiBwcmludHMgdGhlIHJlc3VsdHMgZm9yIHRoZSBsYXN0IGxldmVsIG9mIHRoZSBsYXN0IHRlcm0sIGkuZS4gaGVyZSBpdCB3YXMgZm9yIGZvciB0aGUgaW50ZXJhY3Rpb24gdGVybSBTRk4gdnMuIFVWQiBhdCBXZWVrIDE1IHZzLiBXZWVrIDIuDQogICAgICAgDQojIEdlbmVzIHdpdGggYm90aCBpbnRlcmFjdGlvbnMgYmVpbmcgc2lnbmlmaWNhbnQNCmBgYHtyIHNpZ25faW50fQ0KbGdlbmUuY29uIDwtIHVuaXF1ZShyZXNfaW50X2Nvbl91dmJfd2Vla0Byb3duYW1lc1tyZXNfaW50X2Nvbl91dmJfd2VlayRwYWRqIDwgMC4xXSkNCmxnZW5lLnNmbiA8LSB1bmlxdWUocmVzX2ludF9zZm5fdXZiX3dlZWtAcm93bmFtZXNbcmVzX2ludF9zZm5fdXZiX3dlZWskcGFkaiA8IDAuMV0pDQpsZ2VuZSA8LSBsZ2VuZS5jb25bbGdlbmUuY29uICVpbiUgbGdlbmUuc2ZuXQ0KbGdlbmUgPC0gbGdlbmVbIWlzLm5hKGxnZW5lKV0NCmxnZW5lDQpgYGANCg0KICAgICAgIA0KUGxvdCBvZiBERVNlcS1ub3JtYWxpemVkY291bnRzIG9mIGdlbmVzIHdpdGggc21hbGxlc3QgYWRqdXN0ZWQgcC12YWx1ZSBmb3IgdGhlIGludGVyYWN0aW9uIHRlcm06ICAgICANCmBgYHtyIGRlc2VxMl93ZWVrMl93ZWVrMTVfdG9wOV9kZXNlcW5vcm0sIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSA4fQ0KIyBHZXQgdGhlIERFU2VxLW5vcm1hbGl6ZSBjb3VudHMNCmRwMSA8LSBsaXN0KCkNCmZvciAoaSBpbiAxOmxlbmd0aChsZ2VuZSkpIHsNCiAgb3V0IDwtIHBsb3RDb3VudHMoZGRzLCANCiAgICAgICAgICAgICAgICAgICAgZ2VuZSA9IGxnZW5lW1tpXV0sDQogICAgICAgICAgICAgICAgICAgIGludGdyb3VwID0gYygidHJ0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0aW1lIiksDQogICAgICAgICAgICAgICAgICAgIHJldHVybkRhdGEgPSBUUlVFKQ0KICBkcDFbW2ldXSA8LSBkYXRhLnRhYmxlKEdlbmVpZCA9IGxnZW5lW1tpXV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgU2FtcGxlID0gcm93bmFtZXMob3V0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBvdXQpDQp9DQpkcDEgPC0gcmJpbmRsaXN0KGRwMSkNCmRwMSR0cnQgPC0gZmFjdG9yKGRwMSR0cnQsDQogICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJDT04iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVVZCIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNGTiIpKQ0KZHAxJHRpbWUgPC0gZmFjdG9yKGRwMSR0aW1lLA0KICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIjAydyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTV3IiksDQogICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiV2VlayAyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJXZWVrIDE1IikpDQpkcDEkR2VuZWlkIDwtIGZhY3RvcihkcDEkR2VuZWlkLA0KICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gbGdlbmUpDQpkcDFbLCBtdSA6PSBtZWFuKGNvdW50LA0KICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpLA0KICAgIGJ5ID0gYygiR2VuZWlkIiwNCiAgICAgICAgICAgInRydCIsDQogICAgICAgICAgICJ0aW1lIildDQpkbXUgPC0gdW5pcXVlKGRwMVssIC1jKCJTYW1wbGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAiY291bnQiKV0pDQoNCnAxIDwtIGdncGxvdChkcDEsDQogICAgICAgICAgICAgYWVzKHggPSB0aW1lLA0KICAgICAgICAgICAgICAgICB5ID0gY291bnQsDQogICAgICAgICAgICAgICAgIGdyb3VwID0gdHJ0LA0KICAgICAgICAgICAgICAgICBmaWxsID0gdHJ0KSkgKw0KICBmYWNldF93cmFwKH4gR2VuZWlkLA0KICAgICAgICAgICAgIHNjYWxlID0gImZyZWVfeSIpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICBzaXplID0gNSwNCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBkbXUsDQogICAgICAgICAgICBhZXMoeCA9IHRpbWUsDQogICAgICAgICAgICAgICAgeSA9IG11LA0KICAgICAgICAgICAgICAgIGdyb3VwID0gdHJ0LA0KICAgICAgICAgICAgICAgIGNvbG91ciA9IHRydCksDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICBhbHBoYSA9IDAuNSwNCiAgICAgICAgICAgIHNpemUgPSAyKSArDQogIHNjYWxlX3hfZGlzY3JldGUoIiIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKCJERVNlcS1Ob3JtYWxpemVkIENvdW50cyIpICsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZSgiVHJlYXRtZW50IikNCnByaW50KHAxKQ0KYGBgDQogICAgICANCkNvbXBhcmUgdG8gdGhlIHBsb3Qgb2YgVFBNLW5vcm1hbGl6ZWRjb3VudHMgb2YgZ2VuZXMgd2l0aCBzbWFsbGVzdCBhZGp1c3RlZCBwLXZhbHVlIGZvciB0aGUgaW50ZXJhY3Rpb24gdGVybTogICAgIA0KYGBge3IgZGVzZXEyX3dlZWsyX3dlZWsxNV90cG1ub3JtLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gOH0NCiMgRXhhbWluZSBUUE0gdmFsdWVzIGZvciB0aGUgc2FtZSBnZW5lcw0KdG1wIDwtIHRwbVtHZW5laWQgJWluJSBsZ2VuZSwgXQ0KdG1wJEdlbmVpZCA8LSBmYWN0b3IodG1wJEdlbmVpZCwNCiAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGxnZW5lKQ0KdG1wIDwtIG1lbHQuZGF0YS50YWJsZShkYXRhID0gdG1wLA0KICAgICAgICAgICAgICAgICAgICAgICBpZC52YXJzID0gMSwNCiAgICAgICAgICAgICAgICAgICAgICAgbWVhc3VyZS52YXJzID0gMzpuY29sKHRtcCksDQogICAgICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlLm5hbWUgPSAiU2FtcGxlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUubmFtZSA9ICJUUE0iKQ0KdG1wIDwtIG1lcmdlKGRtZXRhLA0KICAgICAgICAgICAgIHRtcCwNCiAgICAgICAgICAgICBieSA9ICJTYW1wbGUiKQ0KDQpwMSA8LSBnZ3Bsb3QodG1wLA0KICAgICAgICAgICAgIGFlcyh4ID0gV2VlaywNCiAgICAgICAgICAgICAgICAgeSA9IFRQTSwNCiAgICAgICAgICAgICAgICAgZmlsbCA9IFRyZWF0bWVudCwNCiAgICAgICAgICAgICAgICAgZ3JvdXAgPSBUcmVhdG1lbnQpKSArDQogIGZhY2V0X3dyYXAofiBHZW5laWQsDQogICAgICAgICAgICAgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSksDQogICAgICAgICAgICAgc2hhcGUgPSAyMSwNCiAgICAgICAgICAgICBzaXplID0gNSwNCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIpKw0KICBzY2FsZV94X2Rpc2NyZXRlKCIiKQ0KcGxvdChwMSkNCmBgYA0KDQojIFNlc3Npb24gSW5mb3JtYXRpb24NCmBgYHtyIGluZm8sZXZhbD1UUlVFfQ0Kc2Vzc2lvbkluZm8oKQ0KYGBg